Esempio n. 1
0
void main(int argc,char **argv)
{
  char *dir;
  char *sender;
  char *moddir;
  const char *queryext = (char *) 0;
  int opt;
  int ret = 0;
  int dontact = 0;
  unsigned int i,j;
  const char *program;
  stralloc *opts;

  umask(022);
  sig_pipeignore();
	/* storeopts to ezmlm-store only. Others to both (ezmlm-store may */
	/* pass them on to ezmlm-send. */
  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  if (!stralloc_copys(&storeopt,"-")) die_nomem();

  while ((opt = getopt(argc,argv,
      "0cCmMpPq:Q:sSrRt:T:vVyY")) != opteof)
    switch(opt) {	/* pass on unrecognized options */
      case 'c':			/* ezmlm-send flags */
      case 'C':
      case 'r':
      case 'Q':
      case 'R':
        szchar[0] = opt;
        if (!stralloc_append(&sendopt,szchar)) die_nomem();
        if (!stralloc_append(&storeopt,szchar)) die_nomem();
        break;
      case 'm':			/* ezmlm-store flags */
      case 'M':
      case 'p':
      case 'P':
      case 's':
      case 'S':
      case 'y':
      case 'Y':
        szchar[0] = opt;
        if (!stralloc_append(&storeopt,szchar)) die_nomem();
        break;
      case 'q': if (optarg) queryext = optarg; break;
      case 'v':
      case 'V': strerr_die2x(0,"ezmlm-gate version: ",auto_version);
      case '0': dontact = 1; break;
      default:			/* ezmlm-store flags */
        die_usage();
    }

  startup(dir = argv[optind++]);

  sender = env_get("SENDER");

  pmod = (char *) 0;

  if (queryext) {
    getconf(&cmds,queryext,1,dir);
    i = 0;
    for (j = 0;j < cmds.len; ++j)
      if (!cmds.s[j]) {
	switch (cmds.s[i]) {
	  case '\0': case '#': break;	/* ignore blank/comment */
	  case '|':
		ret = mailprog(cmds.s + i + 1); break;
	  default:
		ret = mailprog(cmds.s + i); break;
	}
	if (ret) break;
	i = j + 1;
    }
    if (!ret || ret == 99)		/* 111 => temp error */
      pmod = "";			/* 0, 99 => post */
					/* other => moderate */
  }
  moddir = argv[optind++];
  if (moddir && !ret) {			/* if exit 0 and moddir, add issub */
    pmod = (char *) 0;
    while (moddir && !pmod && sender) {
      pmod = (moddir[0] == '/')
	? issub(moddir,0,sender)
	: issub(dir,moddir,sender);
      closesub();
      moddir = argv[optind++];
    }
  }

  if (pmod) {
    program = "/ezmlm-send";
    opts = &sendopt;
  }
  else {
    program = "/ezmlm-store";
    opts = &storeopt;
  }

  if (dontact) {
    substdio_puts(subfderr, auto_bin);
    substdio_puts(subfderr, program);
    substdio_put(subfderr, " ", 1);
    substdio_put(subfderr, opts->s, opts->len);
    substdio_put(subfderr, " ", 1);
    substdio_puts(subfderr, dir);
    substdio_putsflush(subfderr, "\n");
    _exit(0);
  }

  if ((child = wrap_fork()) == 0)
    wrap_execbin(program, opts, dir);
  /* parent */
  wrap_exitcode(child);
  _exit(0);
}
Esempio n. 2
0
void main()
{
  int i;
  int numcolons;

  umask(033);
  if (chdir(auto_qmail) == -1) die_chdir();

  fd = open_read("users/assign");
  if (fd == -1) die_opena();

  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));

  fdtemp = open_trunc("users/cdb.tmp");
  if (fdtemp == -1) die_opent();

  if (cdbmss_start(&cdbmss,fdtemp) == -1) die_writet();

  if (!stralloc_copys(&wildchars,"")) die_nomem();

  for (;;) {
    if (getln(&ssin,&line,&match,'\n') != 0) die_reada();
    if (line.len && (line.s[0] == '.')) break;
    if (!match) die_format();

    if (byte_chr(line.s,line.len,'\0') < line.len) die_format();
    i = byte_chr(line.s,line.len,':');
    if (i == line.len) die_format();
    if (i == 0) die_format();
    if (!stralloc_copys(&key,"!")) die_nomem();
    if (line.s[0] == '+') {
      if (!stralloc_catb(&key,line.s + 1,i - 1)) die_nomem();
      case_lowerb(key.s,key.len);
      if (i >= 2)
	if (byte_chr(wildchars.s,wildchars.len,line.s[i - 1]) == wildchars.len)
	  if (!stralloc_append(&wildchars,line.s + i - 1)) die_nomem();
    }
    else {
      if (!stralloc_catb(&key,line.s + 1,i - 1)) die_nomem();
      if (!stralloc_0(&key)) die_nomem();
      case_lowerb(key.s,key.len);
    }

    if (!stralloc_copyb(&data,line.s + i + 1,line.len - i - 1)) die_nomem();

    numcolons = 0;
    for (i = 0;i < data.len;++i)
      if (data.s[i] == ':') {
	data.s[i] = 0;
	if (++numcolons == 6)
	  break;
      }
    if (numcolons < 6) die_format();
    data.len = i;

    if (cdbmss_add(&cdbmss,key.s,key.len,data.s,data.len) == -1) die_writet();
  }

  if (cdbmss_add(&cdbmss,"",0,wildchars.s,wildchars.len) == -1) die_writet();

  if (cdbmss_finish(&cdbmss) == -1) die_writet();
  if (fsync(fdtemp) == -1) die_writet();
  if (close(fdtemp) == -1) die_writet(); /* NFS stupidity */
  if (rename("users/cdb.tmp","users/cdb") == -1) die_rename();

  _exit(0);
}
Esempio n. 3
0
static void die_syntax(stralloc *line)
{
  if (!stralloc_0(line)) die_nomem();
  strerr_die4x(100,FATAL,MSG1(ERR_SYNTAX,TXT_EZCRONRC),": ",line->s);
}
Esempio n. 4
0
void digest(msgentry *msgtable,
	    subentry *subtable,
	    authentry *authtable,
	    unsigned long from,unsigned long to,
	    stralloc *subj,int factype,char format)
/* Output digest range from-to as per msgtable/subtable (from mkthread(s)). */
/* "Subject is the subject of the _entire_ digest/set. */
{
  const msgentry *pmsgt;
  subentry *psubt;
  const char *cp;
  int ffirstmsg;
  unsigned int len;
  unsigned long msg;
  unsigned long subnum;

  psubt = subtable;
  presub(from,to,subj,factype,format);

  if (format != NATIVE) {
    while (psubt->sub) {
      ffirstmsg = 1;
		/* ptr to first message with this subject */
      pmsgt = msgtable + psubt->firstmsg - from;
      subnum = (unsigned long) (psubt - subtable +1);
      for (msg=psubt->firstmsg; msg<=to; msg++) {
        if (pmsgt->subnum == subnum) {
          if(ffirstmsg) {
            ffirstmsg = 0;
            if (!stralloc_copys(&line,"\n")) die_nomem();
	    if (psubt->sublen <= HASHLEN + 2) {
              if (!stralloc_cats(&line,"(null)\n")) die_nomem();
	    } else
              if (!stralloc_catb(&line,psubt->sub + HASHLEN + 1,
		psubt->sublen - HASHLEN - 1)) die_nomem();
          } else
            if (!stralloc_copys(&line,"")) die_nomem();
          if (!stralloc_cats(&line,"\t")) die_nomem();
          if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msg))) die_nomem();
          if (!stralloc_append(&line," ")) die_nomem();
          if (pmsgt->authnum) {
	    author.len = 0;
	    cp = authtable[pmsgt->authnum - 1].auth;
	    len = authtable[pmsgt->authnum - 1].authlen - 1;
	    if (len > HASHLEN) {
              if (!stralloc_catb(&author,cp + HASHLEN + 1,
		len - HASHLEN - 1)) die_nomem();
	    } else
	      if (!stralloc_catb(&author,cp,len)) die_nomem();
	    if (!stralloc_0(&author)) die_nomem();
	  }
          if (!stralloc_cats(&line,MSG1(TXT_BY,author.s))) die_nomem();
	  if (!stralloc_append(&line,"\n")) die_nomem();
          code_qput(line.s,line.len);
        }
        pmsgt++;
      }
      psubt++;
    }
  }
  postsub(factype,format);

  psubt = subtable;
  while (psubt->sub) {
    pmsgt = msgtable + psubt->firstmsg - from;
    subnum = (unsigned long) (psubt - subtable +1);
    for (msg=psubt->firstmsg; msg<=to; msg++) {
      if (pmsgt->subnum == subnum)
        msgout(msg,format);
      pmsgt++;
    }
    psubt++;
  }
  postmsg(format);
  idx_destroythread(msgtable,subtable,authtable);
}
Esempio n. 5
0
static void
entry_add(lx_s *body, struct dirent *dent)
{
    char *dt;
    char *dname = dent->d_name;
    struct stat sb;
    lx_s mode = {0};
    lx_s size = {0};
    unsigned perms;

#ifdef HAVE_D_NAMLEN    /* XXX: add to configuration */
    unsigned dnamlen = dent->d_namlen;
#else
    unsigned dnamlen = strlen(dname);
#endif

    if (!strcmp(dname, ".")) return;

    /* XXX: make lstat()? with stat(), symlinks could cause confusion */
    if (stat(dname, &sb)) {
        /* XXX: should probably be debug, really, since symbolic links to
         * invalid filenames will trigger this */
        log_warning(ERRNO, dname, "stat");
        return;
    }

    if (S_ISDIR(sb.st_mode)) {
        dt = DTNAM_DIR;
        /* replace terminating 0 with '/' for our usage */
        dname[dnamlen++] = '/';
    } else if (S_ISREG(sb.st_mode)) {
        dt = DTNAM_FILE;
    } else {
        dt = DTNAM_OTHER;
    }

    /* get ascii representation of numerical mode */
    perms = sb.st_mode & 07777;
    if (lx_setalloc(&mode, 5)) die_nomem();
    if (perms >= 01000)
        lx_cadd(&mode, '0');
    else {
        lx_striadd(&mode, " 0", 2);
        if (perms < 0100) {
            lx_cadd(&mode, '0');
            if (perms < 010) {
                lx_cadd(&mode, '0');
            }
        }
    }
    lx_straddulong(&mode, perms, 8);


    /* get a normalized size value */

#define kmask 0xff
#define kshrink(n, type) \
    ((type) (((type)n & ~(type)kmask) + (kmask+1)) >> 10)
    {
        char type = 'b';
        off_t len = sb.st_size;

        if (lx_setalloc(&size, 5)) die_nomem();

        if (len >= 4096) {
            len  = kshrink(len, off_t);
            type = 'k';
        }
        if (len >= 4096) {
            len  = kshrink(len, off_t);
            type = 'm';
        }
        if (len >= 4096) {
            len  = kshrink(len, off_t);
            type = 'g';
        }
        if (len < 1000) {
            lx_cadd(&size, ' ');
            if (len < 100) {
                lx_cadd(&size, ' ');
                if (len < 10)
                    lx_cadd(&size, ' ');
            }
        }
        if (lx_straddulong(&size, len, 10)) die_nomem();
        if (lx_cadd(&size, type)) die_nomem();
    }

    if (lx_striadd(body, "   ", 3) ||
        lx_stradd(body, dt) ||
        lx_cadd(body, ' ') ||
        lx_strcat(body, &mode) ||
        lx_striadd(body, "  ", 2) ||
        lx_strcat(body, &size) ||
        lx_stradd(body, "  <a href=\"") ||
        lx_striadd(body, dname, dnamlen) ||
        lx_striadd(body, "\">", 2) ||
        lx_striadd(body, dname, dnamlen) ||
        lx_stradd(body, "</a>"CRLF)) die_nomem();

    lx_free(&mode);
    lx_free(&size);
}
Esempio n. 6
0
void util_trie_insert(struct trie *t, const char *s)
{
  char *v = strdup(s);
  if (!v) die_nomem();
  if (trie_insert(t, v, v) < 0) die_nomem();
}
Esempio n. 7
0
void copymsg(int fd,char format)
/* Copy archive message "msg" itself from open file handle fd, in "format" */
{
  int match;
  int flaginheader;
  int flagskipblanks;
  int flaggoodfield;

  switch(format) {
    case VIRGIN:
    case NATIVE:
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      for (;;) {
        if (getln(&sstext,&line,&match,'\n') == -1)
           strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s));
        if (match) {
           qmail_put(&qq,line.s,line.len);
	   msgsize += line.len;
        } else
           break;
      }
      break;
    case MIME:
    case MIXED:
      flaginheader = 1;
      flaggoodfield = 0;
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      for (;;) {
        if (getln(&sstext,&line,&match,'\n') == -1)
           strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s));
        if (match) {
          if (flaginheader) {
            if (line.len == 1) {
              flaginheader = 0;
              flaggoodfield = 1;
            } else if (line.s[0] != ' ' && line.s[0] != '\t') {
              flaggoodfield = 0;
              if (constmap(&digheadersmap,line.s,
			byte_chr(line.s,line.len,':')))
                flaggoodfield = 1;
            }
            if (flaggoodfield) {
              qmail_put(&qq,line.s,line.len);		/* header */
	      msgsize += line.len;
	    }
          } else {
            qmail_put(&qq,line.s,line.len);		/* body */
	    msgsize += line.len;
	  }
        } else
          break;
      }
      break;
    case RFC1153:		/* Not worth optimizing. Rarely used */
      flaginheader = 1;
      flagskipblanks = 1;	/* must skip terminal blanks acc to rfc1153 */
      archtype = ' ';		/* rfc1153 requires ordered headers */
      if (!stralloc_copys(&archblanklines,"")) die_nomem();
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      for (;;) {
        if (getln(&sstext,&line,&match,'\n') == -1)
           strerr_die2sys(111,FATAL,MSG1(ERR_READ,line.s));
        if (match) {
          if (flaginheader) {
            if (line.len == 1) {
              flaginheader = 0;
              if (archdate.len) {
                qmail_put(&qq,archdate.s,archdate.len);
                archdate.len = 0;
		msgsize += archdate.len;
              }
              if (archto.len) {
                qmail_put(&qq,archto.s,archto.len);
		msgsize += archto.len;
                archto.len = 0;
              }
              if (archfrom.len) {
                qmail_put(&qq,archfrom.s,archfrom.len);
		msgsize += archfrom.len;
                archfrom.len = 0;
              }
              if (archcc.len) {
                qmail_put(&qq,archcc.s,archcc.len);
		msgsize += archcc.len;
                archcc.len = 0;
              }
              if (archsubject.len) {
                qmail_put(&qq,archsubject.s,archsubject.len);
		msgsize += archsubject.len;
                archsubject.len = 0;
              }
              if (archmessageid.len) {
                qmail_put(&qq,archmessageid.s,archmessageid.len);
		msgsize += archmessageid.len;
                archmessageid.len = 0;
              }
              if (archkeywords.len) {
                qmail_put(&qq,archkeywords.s,archkeywords.len);
		msgsize += archkeywords.len;
                archkeywords.len = 0;
              }
              qmail_puts(&qq,"\n");
            } else if (line.s[0] == ' ' || line.s[0] == '\t') {
              switch (archtype) {	/* continuation lines */
                case ' ':
                  break;
                case 'D':
                  if (!stralloc_cat(&archdate,&line)) die_nomem(); break;
                case 'F':
                  if (!stralloc_cat(&archfrom,&line)) die_nomem(); break;
                case 'T':
                  if (!stralloc_cat(&archto,&line)) die_nomem(); break;
                case 'C':
                  if (!stralloc_cat(&archcc,&line)) die_nomem(); break;
                case 'S':
                  if (!stralloc_cat(&archsubject,&line)) die_nomem(); break;
                case 'M':
                  if (!stralloc_cat(&archmessageid,&line)) die_nomem(); break;
                case 'K':
                  if (!stralloc_cat(&archkeywords,&line)) die_nomem(); break;
                default:
                  strerr_die2x(111,FATAL,
                      "Program error: Bad archive header type");
              }
            } else {
              archtype = ' ';
              if (case_startb(line.s,line.len,"cc:")) {
                archtype='C';
                if (!stralloc_copy(&archcc,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"date:")) {
                archtype='D';
                if (!stralloc_copy(&archdate,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"from:")) {
                archtype='F';
                if (!stralloc_copy(&archfrom,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"keywords:")) {
                archtype='K';
                if (!stralloc_copy(&archkeywords,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"message-id:")) {
                archtype='M';
                if (!stralloc_copy(&archmessageid,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"subject:")) {
                archtype='S';
                if (!stralloc_copy(&archsubject,&line)) die_nomem();
              }
              else if (case_startb(line.s,line.len,"to:")) {
                archtype='T';
                if (!stralloc_copy(&archto,&line)) die_nomem();
              }
            }
          } else if (line.len == 1) {
            if (!flagskipblanks)
              if (!stralloc_copys(&archblanklines,"\n")) die_nomem();
          } else {
            if (archblanklines.len) {
              qmail_put(&qq,archblanklines.s,archblanklines.len);
              archblanklines.len = 0;
            }
            flagskipblanks = 0;
            qmail_put(&qq,line.s,line.len);
	    msgsize += line.len;
          }
        } else
          break;
      }
      break;
    default:
      strerr_die2x(100,FATAL,"Program error: bad format in copymsg()");
  }
}
Esempio n. 8
0
int findname(void)
/* returns 1 if a matching line was found, 0 otherwise. name will contain */
/* the correct list address in either case */
{
  char *cpat,*cp1,*cp2,*cplast;
  const char *cpname;
  unsigned long u;
  unsigned char hash,hash_hi,hash_lo;
  unsigned int pos,pos_name,pos_hi;
  int fd,match;

  /* make case insensitive hash */
  flagfound = 0;			/* default */
  cpname = "";				/* default */
  if (!stralloc_copy(&lctarget,&target)) die_nomem();
  case_lowerb(lctarget.s,lctarget.len -1);
  hash = subhashs(lctarget.s);

  /* make domain pointer */
  cpat = lctarget.s + str_chr(lctarget.s,'@');
  if (!*cpat)
    strerr_die4x(100,FATAL,ERR_ADDR_AT,": ",target.s);
  cplast = cpat + str_len(cpat) - 1;
  if (*cplast == '.') --cplast;		/* annonying special case */
  cp1 = cpat + byte_rchr(cpat,cplast - cpat, '.');
  if (cp1 != cplast) {			/* got one '.' */
    if (!stralloc_copyb(&domain,cp1 + 1, cplast - cp1)) die_nomem();
    cp2 = cpat + byte_rchr(cpat, cp1 - cpat,'.');
    if (cp2 == cp1) cp2 = cpat;
    ++cp2;
    if (!stralloc_append(&domain,".")) die_nomem();
    if (!stralloc_catb(&domain,cp2, cp1 - cp2)) die_nomem();
  } else				/* no '.' */
    if (!stralloc_copyb(&domain,cpat + 1,cplast - cpat)) die_nomem();
  if (!stralloc_0(&domain)) die_nomem();

  if ((fd = open_read(split)) == -1)
    strerr_die4sys(111,FATAL,ERR_OPEN,split,": ");
  substdio_fdbuf(&sssp,read,fd,spbuf,(int) sizeof(spbuf));
  lineno = 0;
  for (;;) {	/* dom:hash_lo:hash_hi:listaddress */
    if (getln(&sssp,&line,&match,'\n') == -1)
      strerr_die4sys(111,FATAL,ERR_READ,split,": ");
     lineno++;
    if (!match)
      break;
    if (line.s[0] == '#') continue;	/* comment */
    line.s[line.len - 1] = '\0';	/* no need to allow \0 in lines */
    if (!line.s[pos = str_chr(line.s,':')])
      continue;				/* usually blank line */
    line.s[pos] = '\0';
    if (pos == 0 ||			/* no domain */
	  (case_starts(domain.s,line.s))) {	/* or matching domain */
	if (!line.s[++pos]) die_syntax();
	pos_hi = pos + str_chr(line.s + pos,':');
	if (!line.s[pos_hi]) die_syntax();
	pos_hi++;
	(void) scan_ulong(line.s + pos, &u);	/* scan_uint() not in ezmlm */
	hash_lo = (unsigned char) u;
	(void) scan_ulong(line.s + pos_hi, &u);
	hash_hi = (unsigned char) u;
	pos_name = pos_hi + str_chr(line.s + pos_hi,':');
	if (pos_hi == pos_name) hash_hi = 52L;	/* default hi = 52 */
	if (line.s[pos_name]) pos_name++;
	if (hash > hash_hi || hash < hash_lo) continue;	/* not us */
	cpname = line.s + pos_name;
	while (*cpname &&				/* isolate name */
	    (*cpname == ' ' || *cpname == '\t')) cpname++;
	pos = line.len - 2;
	while (pos && (line.s[pos] == '\n' || line.s[pos] == ' ' ||
		line.s[pos] == '\t')) line.s[pos--] = '\0';
	break;
    }
  }
  close(fd);

  if (*cpname) {
    if (!stralloc_copys(&name,cpname)) die_nomem();
    if (byte_chr(name.s,name.len,'@') == name.len) {	/* local sublist */
      if (!stralloc_append(&name,"@")) die_nomem();
      if (!stralloc_cat(&name,&outhost)) die_nomem();
    }
    if (!stralloc_0(&name)) die_nomem();
    return 1;
  } else {			/* match without name or no match =>this list */
    if (!stralloc_copy(&name,&outlocal)) die_nomem();
    if (!stralloc_append(&name,"@")) die_nomem();
    if (!stralloc_cat(&name,&outhost)) die_nomem();
    if (!stralloc_0(&name)) die_nomem();
    return 0;
  }
}
Esempio n. 9
0
void sendnotice(const char *d)
/* sends file pointed to by d to the address in the return-path of the  */
/* message. */
{
  unsigned int x,y;
  const char *err;

      if (qmail_open(&qq, (stralloc *) 0) == -1)
        strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));

      fd = open_read(d);
      if (fd == -1)
        strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,d));
      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      if (getln(&sstext,&line,&match,'\n') == -1) die_read();
      if (!match) die_read();
      if (!case_startb(line.s,line.len,"return-path:")) die_read();
      x = 12 + byte_chr(line.s + 12,line.len-12,'<');
      y = byte_rchr(line.s + x,line.len-x,'>');
      if (x != line.len && x+y != line.len) {
        if (!stralloc_copyb(&to,line.s+x+1, y-1)) die_nomem();
        if (!stralloc_0(&to)) die_nomem();
      } else
        die_read();
      hdr_add2s("Mailing-List: ",MSG(TXT_MAILING_LIST));
      if (listid.len > 0)
	hdr_add2("List-ID: ",listid.s,listid.len);
      hdr_datemsgid(when+msgnum++);
      hdr_from("-help");
      hdr_subject(MSG(SUB_RETURNED_POST));
      hdr_add2s("To: ",to.s);
      if (flagmime) {
	hdr_mime(CTYPE_MULTIPART);
	hdr_boundary(0);
	hdr_ctype(CTYPE_TEXT);
        hdr_transferenc();
      } else
      qmail_puts(&qq,"\n\n");

      copy(&qq,"text/top",flagcd);
      copy(&qq,"text/mod-timeout",flagcd);
      if (flagcd == 'B') {
        encodeB("",0,&line,2);
        qmail_put(&qq,line.s,line.len);
      }

      if (flagmime) {
	hdr_boundary(0);
	hdr_ctype(CTYPE_MESSAGE);
        qmail_puts(&qq,"\n");
      }

      if (seek_begin(fd) == -1)
        strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,d));

      substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
      if (qmail_copy(&qq,&sstext,-1) != 0) die_read();
      close (fd);

      if (flagmime)
	hdr_boundary(1);

      if (!stralloc_copy(&line,&outlocal)) die_nomem();
      if (!stralloc_cats(&line,"-return-@")) die_nomem();
      if (!stralloc_cat(&line,&outhost)) die_nomem();
      if (!stralloc_0(&line)) die_nomem();
      qmail_from(&qq,line.s);		/* sender */
        qmail_to(&qq,to.s);

     if (*(err = qmail_close(&qq)) != '\0')
       strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ", err + 1);

     strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
     strerr_warn2("ezmlm-clean: info: qp ",strnum,0);
}
Esempio n. 10
0
int main(int argc,char **argv)
{
  unsigned long maxmsgsize = 0L;
  unsigned long minmsgsize = 0L;
  unsigned long msgsize = 0L;
  char linetype = ' ';
  char *cp, *cpstart, *cpafter;
  const char *dir;
  const char *err;
  const char *sender;
  unsigned int len;
  int match;

  getconfopt(argc,argv,options,-1,&dir);
  if (dir) {
    startup(dir);
    flagparsemime = 1;		/* only if dir do we have mimeremove/reject */
    if (getconf_line(&line,"msgsize",0)) {
      if (!stralloc_0(&line)) die_nomem();
      len = scan_ulong(line.s,&maxmsgsize);
      if (line.s[len] == ':')
        scan_ulong(line.s+len+1,&minmsgsize);
    }
    if (flagforward) {
      if (!stralloc_copys(&mydtline,"Delivered-To: command forwarder for "))
	die_nomem();
      if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
      if (!stralloc_cats(&mydtline,"@")) die_nomem();
      if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
      if (!stralloc_cats(&mydtline,"\n")) die_nomem();
    }
  } else {
    flagtook = 1;		/* if no "dir" we can't get outlocal/outhost */
    flagforward = 0;		/* nor forward requests */
  }

  sender = get_sender();
  if (!sender)
    die_sender();
  if (!*sender)
    strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));

  if (flagparsemime) {		/* set up MIME parsing */
    if (getconf(&mimeremove,"mimekeep",0))
      mimeremoveflag = 1;
    else
      getconf(&mimeremove,"mimeremove",0);
    constmap_init(&mimeremovemap,mimeremove.s,mimeremove.len,0);
    getconf(&mimereject,"mimereject",0);
    constmap_init(&mimerejectmap,mimereject.s,mimereject.len,0);
  }
  if (flagheaderreject && dir) {
    getconf(&headerreject,"headerreject",0);
    constmap_init(&headerrejectmap,headerreject.s,headerreject.len,0);
  }
  for (;;) {
    if (getln(&ssin,&line,&match,'\n') == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
    if (!match) break;
    if (flagheaderreject && dir)
      if (constmap(&headerrejectmap,line.s,byte_chr(line.s,line.len,':')))
        strerr_die2x(100,FATAL,MSG(ERR_MAILING_LIST));

    if (line.len == 1) break;
    cp = line.s; len = line.len;
    if ((*cp == ' ' || *cp == '\t')) {
      switch(linetype) {
	case 'T': if (!stralloc_catb(&to,cp,len-1)) die_nomem(); break;
	case 'S': if (!stralloc_catb(&subject,cp,len-1)) die_nomem(); break;
	case 'C': if (!stralloc_catb(&content,cp,len-1)) die_nomem(); break;
	case 'P': if (!stralloc_catb(&precd,cp,len-1)) die_nomem(); break;
	default: break;
      }
    } else {
      if (!flagtook &&
		(case_startb(cp,len,"to:") || case_startb(cp,len,"cc:"))) {
	linetype = 'T';		/* cat so that To/Cc don't overwrite */
        if (!stralloc_catb(&to,line.s + 3,line.len - 4)) die_nomem();
      } else if ((flagneedsubject || flagrejectcommands) &&
			 case_startb(cp,len,"subject:")) {
	if (!stralloc_copyb(&subject,cp+8,len-9)) die_nomem();
	linetype = 'S';
      } else if (case_startb(cp,len,"content-type:")) {
	if (!stralloc_copyb(&content,cp+13,len-14)) die_nomem();
	linetype = 'C';
      } else if (case_startb(cp,len,"precedence:")) {
	if (!stralloc_copyb(&precd,cp+11,len-12)) die_nomem();
	linetype = 'P';
      } else {
	if (flagforward && line.len == mydtline.len) {
	  if (!byte_diff(line.s,line.len,mydtline.s))
            strerr_die2x(100,FATAL,MSG(ERR_LOOPING));
        }
        linetype = ' ';
      }
    }
  }
  if (precd.len >= 4 &&
		(!case_diffb(precd.s + precd.len - 4,4,"junk") ||
		!case_diffb(precd.s + precd.len - 4,4,"bulk")))
	  strerr_die1x(99,MSG(ERR_JUNK));	/* ignore precedence junk/bulk */
  cp = subject.s;
  len = subject.len;
  while (len && (cp[len-1] == ' ' || cp[len-1] == '\t')) --len;
  while (len && ((*cp == ' ') || (*cp == '\t'))) { ++cp; --len; }
  flaghavesubject = 1;

  if (flagbody)
    if ((len > 9 && case_starts(cp,"subscribe"))
	|| (len > 11 && case_starts(cp,"unsubscribe")))
      flaghavecommand = 1;

  switch(len) {
    case 0: flaghavesubject = 0; break;
    case 4: if (!case_diffb("help",4,cp)) flaghavecommand = 1; break;
    case 6:	/* Why can't they just leave an empty subject empty? */
	    if (!case_diffb("(null)",6,cp))
              flaghavesubject = 0;
            else
	    if (!case_diffb("(none)",6,cp))
              flaghavesubject = 0;
            else
              if (!case_diffb("remove",6,cp))
	        flaghavecommand = 1;
            break;
    case 9: if (!case_diffb("subscribe",9,cp)) flaghavecommand = 1; break;
    case 11: if (!case_diffb("unsubscribe",11,cp)) flaghavecommand = 1; break;
    case 12: if (!case_diffb("(no subject)",12,cp)) flaghavesubject = 0; break;
    default: break;
  }

  if (!flagtook && !getto(&to))
    strerr_die2x(exitquiet,FATAL,MSG(ERR_NO_ADDRESS));

  if (flagneedsubject && !flaghavesubject)
    strerr_die2x(100,FATAL,MSG(ERR_NO_SUBJECT));

  if (flagrejectcommands && flaghavecommand) {
    if (flagforward) {			/* flagforward => forward */
      if (qmail_open(&qq) == -1)	/* open queue */
	strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));
      qmail_put(&qq,mydtline.s,mydtline.len);
      if (seek_begin(0) == -1)
	strerr_die2sys(111,FATAL,MSG(ERR_SEEK_INPUT));
      if (qmail_copy(&qq,&ssin2,copylines) != 0)
	strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
      if (!stralloc_copy(&to,&outlocal)) die_nomem();
      if (!stralloc_cats(&to,"-request@")) die_nomem();
      if (!stralloc_cat(&to,&outhost)) die_nomem();
      if (!stralloc_0(&to)) die_nomem();
      qmail_from(&qq,sender);
      qmail_to(&qq,to.s);
      if (*(err = qmail_close(&qq)) == '\0') {
        strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
        strerr_die2x(99,"ezmlm-request: info: forward qp ",strnum);
      } else
        strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);
    } else
      strerr_die2x(100,FATAL,MSG(ERR_SUBCOMMAND));
  }

  if (content.len) {			/* MIME header */
    cp = content.s;
    len = content.len;
    while (len && (*cp == ' ' || *cp == '\t')) { ++cp; --len; }
    cpstart = cp;
    if (*cp == '"') {			/* might be commented */
      ++cp; cpstart = cp;
      while (len && *cp != '"') { ++cp; --len; }
    } else {
      while (len && *cp != ' ' && *cp != '\t' && *cp != ';') {
        ++cp; --len;
      }
    }

    if (flagparsemime)
      if ((!!constmap(&mimeremovemap,cpstart,cp-cpstart) ^ mimeremoveflag) ||
	  constmap(&mimerejectmap,cpstart,cp-cpstart)) {
	*(cp) = (char) 0;
	strerr_die2x(100,FATAL,MSG1(ERR_BAD_TYPE,cpstart));
      }

    cpafter = content.s+content.len;
    while((cp += byte_chr(cp,cpafter-cp,';')) != cpafter) {
      ++cp;
      while (cp < cpafter && (*cp == ' ' || *cp == '\t')) ++cp;
      if (case_startb(cp,cpafter - cp,"boundary=")) {
        cp += 9;			/* after boundary= */
        if (cp < cpafter && *cp == '"') {
          ++cp;
          cpstart = cp;
          while (cp < cpafter && *cp != '"') ++cp;
	  if (cp == cpafter)
		strerr_die1x(100,MSG(ERR_MIME_QUOTE));
        } else {
          cpstart = cp;
          while (cp < cpafter &&
             *cp != ';' && *cp != ' ' && *cp != '\t') ++cp;
        }
        if (!stralloc_copys(&boundary,"--")) die_nomem();
        if (!stralloc_catb(&boundary,cpstart,cp-cpstart))
		die_nomem();
	break;
      }
    }		/* got boundary, now parse for parts */
  }

  for (;;) {
    if (getln(&ssin,&line,&match,'\n') == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
    if (!match) break;
    if (line.len == 1) {
      flagcheck = 0;
      continue;
		/* Doesn't do continuation lines. _very_ unusual, and worst */
		/* case one slips through that shouldn't have */
    } else if (flagcheck && case_startb(line.s,line.len,"content-type:")) {
        cp = line.s + 13;
	len = line.len - 14;			/* zap '\n' */
        while (*cp == ' ' || *cp == '\t') { ++cp; --len; }
        cpstart = cp;
	if (*cp == '"') {			/* quoted */
	  ++cp; cpstart = cp;
	  while (len && *cp != '"') { ++cp; --len; }
        } else {				/* not quoted */
          while (len && *cp != ' ' && *cp != '\t' && *cp != ';') {
	    ++cp; --len;
	  }
        }
	if (flagparsemime && constmap(&mimerejectmap,cpstart,cp-cpstart)) {
          *cp = '\0';
          strerr_die2x(100,FATAL,MSG1(ERR_BAD_PART,cpstart));
        }
    } else if (boundary.len && *line.s == '-' && line.len > boundary.len &&
	!str_diffn(line.s,boundary.s,boundary.len)) {
        flagcheck = 1;
    } else {
      if (!msgsize && flagbody)
	if (case_startb(line.s,line.len,"subscribe") ||
		case_startb(line.s,line.len,"unsubscribe"))
	  strerr_die2x(100,FATAL,MSG(ERR_BODYCOMMAND));
      if (!flagcheck) {
	  msgsize += line.len;
	  if (maxmsgsize && msgsize > maxmsgsize) {
	    strnum[fmt_ulong(strnum,maxmsgsize)] = 0;
	    strerr_die2x(100,FATAL,MSG1(ERR_MAX_SIZE,strnum));
	  }
      }
    }
  }
  if (msgsize < minmsgsize) {
    strnum[fmt_ulong(strnum,minmsgsize)] = 0;
        strerr_die2x(100,FATAL,MSG1(ERR_MIN_SIZE,strnum));
  }
  _exit(0);
}
Esempio n. 11
0
void main(int argc,char **argv)
{
  char *dir;
  char *action;
  char *dtline;
  char *nhost;
  const char *err;
  unsigned int i;
  int match;
  int opt;

  sig_pipeignore();

  while ((opt = getopt(argc,argv,"dDvV")) != opteof) {
    switch (opt) {
    case 'd': flagdo = 1; break;
    case 'D': flagdo = 0; break;
    case 'v':
    case 'V':
      strerr_die2x(0, "ezmlm-split version: ",auto_version);
    default:
      die_usage();
    }
  }

  startup(dir = argv[optind++]);
  load_config(dir);
  if (!(split = argv[optind]))
    split = "split";

  if (flagdo) {
    sender = env_get("SENDER");
    if (!sender) strerr_die2x(100,FATAL,ERR_NOSENDER);
    if (!*sender)
      strerr_die2x(100,FATAL,ERR_BOUNCE);
    if (!sender[str_chr(sender,'@')])
      strerr_die2x(100,FATAL,ERR_ANONYMOUS);
    if (str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,ERR_BOUNCE);

    action = env_get("DEFAULT");
    if (!action) strerr_die2x(100,FATAL,ERR_NODEFAULT);
    if (!stralloc_copys(&target,sender)) die_nomem();
    if (action[0]) {
      i = str_chr(action,'-');
      if (action[i]) {
        action[i] = '\0';
        if (!stralloc_copys(&target,action + i + 1)) die_nomem();
        i = byte_rchr(target.s,target.len,'=');
        if (i < target.len)
	  target.s[i] = '@';
      }
    }
    if (!stralloc_0(&target)) die_nomem();

    if (case_diffs(action,ACTION_SUBSCRIBE) &&
      case_diffs(action,ALT_SUBSCRIBE) &&
      case_diffs(action,ACTION_UNSUBSCRIBE) &&
      case_diffs(action,ALT_UNSUBSCRIBE))
    _exit(0);			/* not for us */

    if (findname()) {
				/* new sender */
      if (!stralloc_copy(&from,&outlocal)) die_nomem();
      if (!stralloc_cats(&from,"-return-@")) die_nomem();
      if (!stralloc_cat(&from,&outhost)) die_nomem();
      if (!stralloc_0(&from)) die_nomem();
      nhost = name.s + str_rchr(name.s,'@');		/* name must have '@'*/
      *(nhost++) = '\0';
      if (!stralloc_copys(&to,name.s)) die_nomem();	/* local */
      if (!stralloc_append(&to,"-")) die_nomem();	/* - */
      if (!stralloc_cats(&to,action)) die_nomem();	/* subscribe */
      if (!stralloc_append(&to,"-")) die_nomem();	/* - */
      if (target.s[i = str_rchr(target.s,'@')])
	target.s[i] = '=';
      if (!stralloc_cats(&to,target.s)) die_nomem();	/* target */
      if (!stralloc_append(&to,"@")) die_nomem();	/* - */
      if (!stralloc_cats(&to,nhost)) die_nomem();	/* host */
      if (!stralloc_0(&to)) die_nomem();
      dtline = env_get("DTLINE");
      if (!dtline) strerr_die2x(100,FATAL,ERR_NODTLINE);

      if (qmail_open(&qq,(stralloc *) 0) == -1)
        strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);
      qmail_puts(&qq,dtline);				/* delivered-to */
      if (qmail_copy(&qq,subfdin,0) != 0)
        strerr_die2sys(111,FATAL,ERR_READ_INPUT);
      qmail_from(&qq,from.s);
      qmail_to(&qq,to.s);

      if (*(err = qmail_close(&qq)) != '\0')
        strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err + 1);

      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
      strerr_die3x(99,INFO,"qp ",strnum);
    }
    _exit(0);
  } else {

    for (;;) {
      if (getln(subfdin,&line,&match,'\n') == -1)
	  strerr_die2sys(111,FATAL,ERR_READ_INPUT);
      if (!match) break;
      if (line.len == 1) continue;	/* ignore blank lines */
      if (line.s[0] == '#') continue;	/* ignore comments */
      if (!stralloc_copy(&target,&line)) die_nomem();
      target.s[target.len - 1] = '\0';
      (void) findname();
      if (!stralloc_cats(&name,": ")) die_nomem();
      if (!stralloc_cats(&name,target.s)) die_nomem();
      if (!stralloc_append(&name,"\n")) die_nomem();
      if (substdio_put(subfdout,name.s,name.len) == -1)
	strerr_die2sys(111,ERR_WRITE,"output: ");
    }
    if (substdio_flush(subfdout) == -1)
      strerr_die2sys(111,ERR_FLUSH,"output: ");
    _exit(0);
  }
  (void)argc;
}
Esempio n. 12
0
void main(int argc,char **argv)
{
  char *dir;
  int fdlock;
  char *sender;
  int match;
  int flaginheader;
  int flagmodpost;
  int flagremote;
  const char *pmod;
  const char *err;
  int opt;
  unsigned int i;
  char szchar[2] = "-";
  int child;

  (void) umask(022);
  sig_pipeignore();

  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  while ((opt = getopt(argc,argv,"bBcCmMpPrRsSvVyY")) != opteof)
    switch(opt) {
      case 'b': flagbody = 1; break;
      case 'B': flagbody = 0; break;
      case 'm': flagmime = 1; break;
      case 'M': flagmime = 0; break;
      case 'p': flagpublic = 1; break;	/* anyone can post (still moderated)*/
      case 'P': flagpublic = 0; break;	/* only moderators can post */
      case 's': flagself = 1; break;	/* modpost and DIR/mod diff fxns */
      case 'S': flagself = 0; break;	/* same fxn */
      case 'y': flagconfirm = 1; break; /* force post confirmation */
      case 'Y': flagconfirm = 0; break; /* disable post confirmation */
      case 'c':				/* ezmlm-send flags */
      case 'C':
      case 'r':
      case 'R':
        szchar[0] = (char) opt & 0xff;
        if (!stralloc_append(&sendopt,szchar)) die_nomem();
        break;
      case 'v':
      case 'V': strerr_die2x(0,"ezmlm-store version: ",auto_version);
      default:
	die_usage();
    }

  sender = env_get("SENDER");

  if (sender) {
    if (!*sender || str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,ERR_BOUNCE);
  }

  startup(dir = argv[optind]);
  load_config(dir);

  if (flagconfirm == -1)
    flagconfirm = getconf_line(&confirmpost,"confirmpost",0,dir);
  else
    getconf_line(&confirmpost,"confirmpost",0,dir);

  flagmodpost = getconf_line(&moderators,"modpost",0,dir);
  flagremote = getconf_line(&line,"remote",0,dir);
  if (!flagmodpost && !flagconfirm) {	/* not msg-mod. Pipe to ezmlm-send */
    if ((child = wrap_fork()) == 0)
      wrap_execbin("/ezmlm-send", &sendopt, dir);
    /* parent */
    wrap_exitcode(child);
  }

  if (!moderators.len || !(moderators.s[0] == '/')) {
    if (!stralloc_copys(&moderators,dir)) die_nomem();
    if (!stralloc_cats(&moderators,"/mod")) die_nomem();
  }
  if (!stralloc_0(&moderators)) die_nomem();

  if (sender) {
      pmod = issub(moderators.s,0,sender);
      closesub();
				/* sender = moderator? */
  } else
    pmod = 0;

  if (!pmod && !flagpublic)
    strerr_die2x(100,FATAL,ERR_NO_POST);

  fdlock = lockfile("mod/lock");

  if (!stralloc_copys(&mydtline, flagconfirm
    ? "Delivered-To: confirm to "
    : "Delivered-To: moderator for ")) die_nomem();
  if (!stralloc_catb(&mydtline,outlocal.s,outlocal.len)) die_nomem();
  if (!stralloc_append(&mydtline,"@")) die_nomem();
  if (!stralloc_catb(&mydtline,outhost.s,outhost.len)) die_nomem();
  if (!stralloc_cats(&mydtline,"\n")) die_nomem();

  if (!stralloc_copys(&returnpath,"Return-Path: <")) die_nomem();
  if (sender) {
    if (!stralloc_cats(&returnpath,sender)) die_nomem();
    for (i = 14; i < returnpath.len;++i)
      if (returnpath.s[i] == '\n' || !returnpath.s[i] )
        returnpath.s[i] = '_';
		/* NUL and '\n' are bad, but we don't quote since this is */
		/* only for ezmlm-moderate, NOT for SMTP */
  }
  if (!stralloc_cats(&returnpath,">\n")) die_nomem();

 pid = getpid();		/* unique file name */
 for (i = 0;;++i)		/* got lock - nobody else can add files */
  {
   when = now();		/* when is also used later for date! */
   if (!stralloc_copys(&fnmsg, flagconfirm?"mod/unconfirmed/":"mod/pending/")) die_nomem();
   if (!stralloc_copyb(&fnbase,strnum,fmt_ulong(strnum,when))) die_nomem();
   if (!stralloc_append(&fnbase,".")) die_nomem();
   if (!stralloc_catb(&fnbase,strnum,fmt_ulong(strnum,pid))) die_nomem();
   if (!stralloc_cat(&fnmsg,&fnbase)) die_nomem();
   if (!stralloc_0(&fnmsg)) die_nomem();
   if (stat(fnmsg.s,&st) == -1) if (errno == error_noent) break;
   /* really should never get to this point */
   if (i == 2)
     strerr_die2x(111,FATAL,ERR_UNIQUE);
   sleep(2);
  }

  if (!stralloc_copys(&action,"-")) die_nomem();
  if (!stralloc_cats(&action,flagconfirm?ACTION_DISCARD:ACTION_REJECT)) die_nomem();
  if (!stralloc_cat(&action,&fnbase)) die_nomem();
  if (!stralloc_0(&action)) die_nomem();
  makeacthash(&action);
  if (!quote(&quoted,&outlocal)) die_nomem();
  if (!stralloc_copy(&reject,&quoted)) die_nomem();
  if (!stralloc_cat(&reject,&action)) die_nomem();
  if (!stralloc_0(&reject)) die_nomem();

  if (!stralloc_copys(&action,"-")) die_nomem();
  if (!stralloc_cats(&action,flagconfirm?ACTION_CONFIRM:ACTION_ACCEPT)) die_nomem();
  if (!stralloc_cat(&action,&fnbase)) die_nomem();
  if (!stralloc_0(&action)) die_nomem();
  makeacthash(&action);
  if (!stralloc_copy(&accept,&quoted)) die_nomem();
  if (!stralloc_cat(&accept,&action)) die_nomem();
  if (!stralloc_0(&accept)) die_nomem();

  set_cptarget(accept.s);	/* for copy () */
  set_cpconfirm(reject.s,quoted.len);

  fdmsg = open_trunc(fnmsg.s);
  if (fdmsg == -1)
    strerr_die6sys(111,FATAL,ERR_WRITE,dir,"/",fnmsg.s,": ");
  substdio_fdbuf(&ssmsg,write,fdmsg,msgbuf,sizeof(msgbuf));

  if (qmail_open(&qq, (stralloc *) 0) == -1)		/* Open mailer */
    strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);

  hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len);
  if (listid.len > 0)
    hdr_add2("List-ID: ",listid.s,listid.len);
  hdr_datemsgid(when);
  if (flagconfirm)
    hdr_from("-owner");
  else
    hdr_add2s("From: ",reject.s);
  hdr_add2s("Reply-To: ",accept.s);
  if (!flagconfirm && !pmod && flagremote) {	/* if remote admin add -allow- address */
    qmail_puts(&qq,"Cc: ");	/* for ezmlm-gate users */
    strnum[fmt_ulong(strnum,(unsigned long) when)] = 0;
    cookie(hash,key.s,key.len-FLD_ALLOW,strnum,sender,"t");
    if (!stralloc_copy(&line,&outlocal)) die_nomem();
    if (!stralloc_cats(&line,"-allow-tc.")) die_nomem();
    if (!stralloc_cats(&line,strnum)) die_nomem();
    if (!stralloc_append(&line,".")) die_nomem();
    if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
    if (!stralloc_append(&line,"-")) die_nomem();
    i = str_rchr(sender,'@');
    if (!stralloc_catb(&line,sender,i)) die_nomem();
    if (sender[i]) {
      if (!stralloc_append(&line,"=")) die_nomem();
      if (!stralloc_cats(&line,sender + i + 1)) die_nomem();
    }
    qmail_put(&qq,line.s,line.len);
    qmail_puts(&qq,"@");
    qmail_put(&qq,outhost.s,outhost.len);
    qmail_puts(&qq,"\n");
  }
  qmail_puts(&qq,"To: <");
  if (flagconfirm) {
    if (sender)
      qmail_puts(&qq, sender);
  } else {
    if (!quote(&quoted,&outlocal))
      die_nomem();
    qmail_put(&qq,quoted.s,quoted.len);
    qmail_puts(&qq,"-moderators@");
    qmail_put(&qq,outhost.s,outhost.len);
  }
  qmail_puts(&qq,">\n");
  /* FIXME: Drop the custom subject hack and use hdr_listsubject1 */
  if (!stralloc_copys(&subject,"Subject: ")) die_nomem();
  if (flagconfirm) {
    if (confirmpost.len) {
      if (!stralloc_cat(&subject,&confirmpost)) die_nomem();
      if (!stralloc_cats(&subject," ")) die_nomem();
    } else {
      if (!stralloc_cats(&subject,TXT_CONFIRM_POST)) die_nomem();
    }
  } else {
    if (!stralloc_cats(&subject,TXT_MODERATE)) die_nomem();
  }
  if (!quote(&quoted,&outlocal)) die_nomem();
  if (!stralloc_cat(&subject,&quoted)) die_nomem();
  if (!stralloc_append(&subject,"@")) die_nomem();
  if (!stralloc_cat(&subject,&outhost)) die_nomem();
  if (flagmime) {
    hdr_mime(CTYPE_MULTIPART);
    qmail_put(&qq,subject.s,subject.len);
    hdr_boundary(0);
    hdr_ctype(CTYPE_TEXT);
    hdr_transferenc();
  } else {
    qmail_put(&qq,subject.s,subject.len);
    qmail_puts(&qq,"\n\n");
  }
  copy(&qq,flagconfirm?"text/post-confirm":"text/mod-request",flagcd);
  if (flagcd == 'B') {
    encodeB("",0,&line,2);
    qmail_put(&qq,line.s,line.len);
  }
  if (substdio_put(&ssmsg,returnpath.s,returnpath.len) == -1) die_msg();
  if (substdio_put(&ssmsg,mydtline.s,mydtline.len) == -1) die_msg();
  substdio_fdbuf(&ssin,read,0,inbuf,sizeof(inbuf));

  if (flagmime) {
    hdr_boundary(0);
    hdr_ctype(CTYPE_MESSAGE);
    qmail_puts(&qq, "\n");
  }

  qmail_put(&qq,returnpath.s,returnpath.len);
  qmail_put(&qq,mydtline.s,mydtline.len);
  flaginheader = 1;
  for (;;) {
    if (getln(&ssin,&line,&match,'\n') == -1)
      strerr_die2sys(111,FATAL,ERR_READ_INPUT);
    if (!match) break;
    if (line.len == 1) flaginheader = 0;
    if (flaginheader) {
      if ((line.len == mydtline.len) &&
		!byte_diff(line.s,line.len,mydtline.s)) {
	close(fdmsg);			/* be nice - clean up */
	unlink(fnmsg.s);
        strerr_die2x(100,FATAL,ERR_LOOPING);
      }
      if (case_startb(line.s,line.len,"mailing-list:")) {
	close(fdmsg);			/* be nice - clean up */
	unlink(fnmsg.s);
        strerr_die2x(100,FATAL,ERR_MAILING_LIST);
      }
    }

    if (flagbody || flaginheader)	/* skip body if !flagbody */
      qmail_put(&qq,line.s,line.len);
    if (substdio_put(&ssmsg,line.s,line.len) == -1) die_msg();
  }

  if (flagmime)
    hdr_boundary(1);

/* close archive before qmail. Loss of qmail will result in re-run, and   */
/* worst case this results in a duplicate msg sitting orphaned until it's */
/* cleaned out.                                                           */

  if (substdio_flush(&ssmsg) == -1) die_msg();
  if (fsync(fdmsg) == -1) die_msg();
  if (fchmod(fdmsg,MODE_MOD_MSG | 0700) == -1) die_msg();
  if (close(fdmsg) == -1) die_msg(); /* NFS stupidity */

  close(fdlock);

  if (flagconfirm) {
    qmail_from(&qq,reject.s);			/* envelope sender */
  } else {
    if (!stralloc_copy(&line,&outlocal)) die_nomem();
    if (!stralloc_cats(&line,"-return-@")) die_nomem();
    if (!stralloc_cat(&line,&outhost)) die_nomem();
    if (!stralloc_0(&line)) die_nomem();
    qmail_from(&qq,line.s);			/* envelope sender */
  }
  if (flagconfirm)				/* to sender */
    qmail_to(&qq,sender);
  else if (pmod)				/* to moderator only */
    qmail_to(&qq,pmod);
  else {
    if (flagself) {				/* to all moderators */
      if (!stralloc_copys(&moderators,dir)) die_nomem();
      if (!stralloc_cats(&moderators,"/mod")) die_nomem();
      if (!stralloc_0(&moderators)) die_nomem();
    }
    putsubs(moderators.s,0,0,52,subto,1);
  }

  if (*(err = qmail_close(&qq)) == '\0') {
      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
      strerr_die2x(0,"ezmlm-store: info: qp ",strnum);
  } else
      strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE,err+1);
}
Esempio n. 13
0
int main(int argc,char **argv)
{
  const char *dir;
  const char *sender;
  const char *moddir;
  int opt;
  int ret = 0;
  unsigned int i,j;
  const char *program;
  stralloc *opts;

  umask(022);
  sig_pipeignore();

  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  if (!stralloc_copys(&storeopt,"-")) die_nomem();
  opt = getconfopt(argc,argv,options,1,&dir);

	/* storeopts to ezmlm-store only. Others to both (ezmlm-store may */
	/* pass them on to ezmlm-send. */
  if (!stralloc_catb(&storeopt,sendopt.s+1,sendopt.len-1)) die_nomem();

  initsub(0);

  sender = get_sender();

  ismod = 0;

  if (queryext) {
    getconf(&cmds,queryext,1);
    i = 0;
    for (j = 0;j < cmds.len; ++j)
      if (!cmds.s[j]) {
	switch (cmds.s[i]) {
	  case '\0': case '#': break;	/* ignore blank/comment */
	  case '|':
		ret = mailprog(cmds.s + i + 1); break;
	  default:
		ret = mailprog(cmds.s + i); break;
	}
	if (ret) break;
	i = j + 1;
    }
    if (!ret || ret == 99)		/* 111 => temp error */
      ismod = 1;			/* 0, 99 => post */
					/* other => moderate */
  }
  moddir = argv[opt++];
  if (moddir && !ret) {			/* if exit 0 and moddir, add issub */
    ismod = 0;
    while (moddir && !ismod && sender) {
      ismod = issub(moddir,sender,0);
      closesub();
      moddir = argv[opt++];
    }
  }

  if (ismod) {
    program = "/ezmlm-send";
    opts = &sendopt;
  }
  else {
    program = "/ezmlm-store";
    opts = &storeopt;
  }

  if (dontact) {
    substdio_puts(subfderr, auto_bin());
    substdio_puts(subfderr, program);
    substdio_put(subfderr, " ", 1);
    substdio_put(subfderr, opts->s, opts->len);
    substdio_put(subfderr, " ", 1);
    substdio_puts(subfderr, dir);
    substdio_putsflush(subfderr, "\n");
    _exit(0);
  }

  if ((child = wrap_fork()) == 0)
    wrap_execbin(program, opts, dir);
  /* parent */
  wrap_exitcode(child);
  _exit(0);
}
Esempio n. 14
0
int main(int argc,char **argv)
{
  char strnum[FMT_ULONG];
  char *action;
  char *dtline;
  char *nhost;
  const char *err;
  unsigned int i;
  int match;
  int opt;

  sig_pipeignore();

  opt = getconfopt(argc,argv,options,1,0);
  if (!(split = argv[opt]))
    split = "split";

  if (flagdo) {
    sender = get_sender();
    if (!sender) die_sender();
    if (!*sender)
      strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));
    if (!sender[str_chr(sender,'@')])
      strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS));
    if (str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));

    action = env_get("DEFAULT");
    if (!action) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT));
    if (!stralloc_copys(&target,sender)) die_nomem();
    if (action[0]) {
      i = str_chr(action,'-');
      if (action[i]) {
        action[i] = '\0';
        if (!stralloc_copys(&target,action + i + 1)) die_nomem();
        i = byte_rchr(target.s,target.len,'=');
        if (i < target.len)
	  target.s[i] = '@';
      }
    }
    if (!stralloc_0(&target)) die_nomem();

    if (case_diffs(action,ACTION_SUBSCRIBE) &&
      case_diffs(action,ALT_SUBSCRIBE) &&
      case_diffs(action,ACTION_UNSUBSCRIBE) &&
      case_diffs(action,ALT_UNSUBSCRIBE))
    _exit(0);			/* not for us */

    if (findname()) {
				/* new sender */
      if (!stralloc_copy(&from,&outlocal)) die_nomem();
      if (!stralloc_cats(&from,"-return-@")) die_nomem();
      if (!stralloc_cat(&from,&outhost)) die_nomem();
      if (!stralloc_0(&from)) die_nomem();
      nhost = name.s + str_rchr(name.s,'@');		/* name must have '@'*/
      *(nhost++) = '\0';
      if (!stralloc_copys(&to,name.s)) die_nomem();	/* local */
      if (!stralloc_append(&to,'-')) die_nomem();	/* - */
      if (!stralloc_cats(&to,action)) die_nomem();	/* subscribe */
      if (!stralloc_append(&to,'-')) die_nomem();	/* - */
      if (target.s[i = str_rchr(target.s,'@')])
	target.s[i] = '=';
      if (!stralloc_cats(&to,target.s)) die_nomem();	/* target */
      if (!stralloc_append(&to,'@')) die_nomem();	/* - */
      if (!stralloc_cats(&to,nhost)) die_nomem();	/* host */
      if (!stralloc_0(&to)) die_nomem();
      dtline = env_get("DTLINE");
      if (!dtline) strerr_die2x(100,FATAL,MSG(ERR_NODTLINE));

      if (qmail_open(&qq) == -1)
        strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));
      qmail_puts(&qq,dtline);				/* delivered-to */
      if (qmail_copy(&qq,subfdin,0) != 0)
        strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
      qmail_from(&qq,from.s);
      qmail_to(&qq,to.s);

      if (*(err = qmail_close(&qq)) != '\0')
        strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);

      strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
      strerr_die3x(99,INFO,"qp ",strnum);
    }
    _exit(0);
  } else {

    for (;;) {
      if (getln(subfdin,&line,&match,'\n') == -1)
	  strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
      if (!match) break;
      if (line.len == 1) continue;	/* ignore blank lines */
      if (line.s[0] == '#') continue;	/* ignore comments */
      if (!stralloc_copy(&target,&line)) die_nomem();
      target.s[target.len - 1] = '\0';
      (void) findname();
      if (!stralloc_cats(&name,": ")) die_nomem();
      if (!stralloc_cats(&name,target.s)) die_nomem();
      if (!stralloc_append(&name,'\n')) die_nomem();
      if (substdio_put(subfdout,name.s,name.len) == -1)
	strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
    }
    if (substdio_flush(subfdout) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_FLUSH_STDOUT));
    _exit(0);
  }
  (void)argc;
}
Esempio n. 15
0
void
resp_sendfile(struct reqinfo *req)
{
    int fd;
    struct stat sb;
    lx_s body = {0},
         data = {0};

    if (lx_check0(&req->location)) die_nomem();
    fd = open(req->location.s, O_RDONLY);
    if (fd < 0) {
        if (errno == ENOENT) {
            die_html(HTERR_NOTFOUND|ERRNO, req->location.s,
                    "couldn't open file for reading", err_not_found);
        }
        die_html(HTERR_FORBID|ERRNO, req->location.s,
                "couldn't open file for reading",
                err_perm_denied);
    }

    if (fstat(fd, &sb)) {
        close(fd);
        /* XXX: 500 instead? */
        die_html(HTERR_FORBID|ERRNO, req->location.s,
                "opened file, but fstat() failed",
                err_perm_denied);
    }

    /* directory? send index (if config option is set) */
    if (S_ISDIR(sb.st_mode) && OPT_INDICES) {
        index_generate(fd, &sb, req, &body);
        close(fd);

        if (lx_strset(&data, "text/html")) die_nomem();
        header_setstr(blob_header_send, "Content-Type", data.s, data.len);

        data.len = 0;
        if (lx_straddulong(&data, body.len, 10)) die_nomem();
        header_setstr(blob_header_send, "Content-Length", data.s, data.len);

        resp_sendprefix(req, HTERR_OK);
        resp_sendheaders(req, blob_header_send);

        if (!global_flags.header_only) {
            if (lx_gdstrput(gd_out, &body)) die_outerr();
        }

        lx_free(&data);
        lx_free(&body);
        return;
    }

    if (!OPT_READABL) {
        close(fd);
        die_html(HTERR_FORBID, 0,
                "Read access forbidden",
                err_perm_denied);
    }

    if (!S_ISREG(sb.st_mode)) {
        close(fd);
        die_html(HTERR_FORBID, req->location.s,
                "not a regular file (may be a dir with 'indexes' unset)",
                err_perm_denied);
    }

    if (lx_strset(&data, "application/octet-stream")) die_nomem();
    header_setstr(blob_header_send, "Content-Type", data.s, data.len);

    data.len = 0;
    if (lx_straddulong(&data, sb.st_size, 10)) die_nomem();
    header_setstr(blob_header_send, "Content-Length", data.s, data.len);

    data.len = 0;
    header_mkdate(&data, sb.st_mtime);
    header_setstr(blob_header_send, "Last-Modified", data.s, data.len);

    resp_sendprefix(req, HTERR_OK);
    resp_sendheaders(req, blob_header_send);

    lx_free(&data);

    if (!global_flags.header_only) {
#define READBUFSIZ 8192
        char buf[READBUFSIZ];
        int r;

        for (;;) {
            r = read(fd, buf, READBUFSIZ);
            if (r < 0) {
                close(fd);
                die_html(HTERR_SERVERR|ERRNO, req->location.s,
                        "file opened, but read failed",
                        err_sys_generic);
            }
            if (sb.st_size < r) {
                log_warning(0, req->location.s,
                        "file longer than file size; truncating.");
                r = sb.st_size;  /* now < READBUFSIZ by definition */
            }

            if (lx_gdputsn(gd_out, buf, r)) die_outerr();
            sb.st_size -= r;

            if (r < READBUFSIZ) break;
        }
        if (sb.st_size) {
            log_warning(0, req->location.s, "premature EOF");
            /* XXX: fill with zeros? */
        }
    }
    close(fd);
}
Esempio n. 16
0
void main(int argc,char **argv)
{
  char *sender;
  char *def;
  char *local;
  char *action;
  int flaginheader;
  int flagcomment;
  int flaggoodfield;
  int flagdone;
  int fd, fdlock;
  int match;
  const char *err;
  char encin = '\0';
  unsigned int start,confnum;
  unsigned int pos,i;
  int child;
  int opt;
  char *cp,*cpnext,*cpfirst,*cplast,*cpafter;

  (void) umask(022);
  sig_pipeignore();
  when = now();

  if (!stralloc_copys(&sendopt,"-")) die_nomem();
  opt = getconfopt(argc,argv,options,1,&dir);

  sender = get_sender();
  if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER));
  local = env_get("LOCAL");
  if (!local) strerr_die2x(100,FATAL,MSG(ERR_NOLOCAL));
  def = env_get("DEFAULT");
  if (!def) strerr_die2x(100,FATAL,MSG(ERR_NODEFAULT));

  if (!*sender)
    strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));
  if (!sender[str_chr(sender,'@')])
    strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS));
  if (str_equal(sender,"#@[]"))
    strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));

  /* local should be >= def, but who knows ... */
  cp = local + str_len(local) - str_len(def) - 2;
  if (cp < local) die_badformat();
  action = local + byte_rchr(local,cp - local,'-');
  if (action == cp) die_badformat();
  action++;

  if (!action[0]) die_badformat();
  if (!str_start(action,ACTION_ACCEPT) && !str_start(action,ACTION_REJECT))
    die_badformat();
  start = str_chr(action,'-');
  if (!action[start]) die_badformat();
  confnum = 1 + start + str_chr(action + start + 1,'.');
  if (!action[confnum]) die_badformat();
  confnum += 1 + str_chr(action + confnum + 1,'.');
  if (!action[confnum]) die_badformat();
  if (!stralloc_copyb(&fnbase,action+start+1,confnum-start-1)) die_nomem();
  if (!stralloc_0(&fnbase)) die_nomem();
  cookie(hash,key.s,key.len,fnbase.s,"","a");
  if (byte_diff(hash,COOKIE,action+confnum+1))
    die_badformat();

  fdlock = lockfile("mod/lock");

  switch(checkfile(fnbase.s)) {
    case 0:
      strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT));
    case -1:			/* only error if new request != action taken */
      if (str_start(action,ACTION_ACCEPT))
        strerr_die2x(0,INFO,MSG(ERR_MOD_ACCEPTED));
      else
        strerr_die2x(100,FATAL,MSG(ERR_MOD_ACCEPTED));
    case -2:
      if (str_start(action,ACTION_REJECT))
        strerr_die2x(0,INFO,MSG(ERR_MOD_REJECTED));
      else
        strerr_die2x(100,FATAL,MSG(ERR_MOD_REJECTED));
    default:
      break;
  }
/* Here, we have an existing filename in fnbase with the complete path */
/* from the current dir in fnmsg. */

  if (str_start(action,ACTION_REJECT)) {

    if (qmail_open(&qq, (stralloc *) 0) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));


				/* Build recipient from msg return-path */
    fd = open_read(fnmsg.s);
    if (fd == -1) {
      if (errno != error_noent)
        strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s));
      else
        strerr_die2x(100,FATAL,MSG(ERR_MOD_TIMEOUT));
    }
    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));

    if (getln(&sstext,&line,&match,'\n') == -1 || !match)
      strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
    maketo();			/* extract SENDER from return-path */
						/* Build message */
    hdr_add2s("Mailing-List: ",MSG(TXT_MAILING_LIST));
    if (listid.len > 0)
      hdr_add2("List-ID: ",listid.s,listid.len);
    hdr_datemsgid(when);
    hdr_from("-owner");
    if (replyto)
      hdr_add2s("Reply-To: ",replyto);
    hdr_add2s("To: ",to.s);
    hdr_subject(MSG(SUB_RETURNED_POST));

    if (flagmime) {
      hdr_mime(CTYPE_MULTIPART);
      hdr_boundary(0);
      hdr_ctype(CTYPE_TEXT);
      hdr_transferenc();
    }
    copy(&qq,"text/top",flagcd);
    copy(&qq,"text/mod-reject",flagcd);

    flagcomment = 0;
    flaginheader = 1;
    if (!stralloc_copys(&text,"")) die_nomem();
    if (!stralloc_ready(&text,1024)) die_nomem(); 
    for (;;) {		/* copy moderator's rejection comment */
      if (getln(subfdin,&line,&match,'\n') == -1)
        strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
      if (!match) break;
      if (flaginheader) {
        if (case_startb(line.s,line.len,"Content-Transfer-Encoding:")) {
          pos = 26;
          while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
          if (case_startb(line.s+pos,line.len-pos,"base64"))
            encin = 'B';
          else if (case_startb(line.s+pos,line.len-pos,"quoted-printable"))
            encin = 'Q';
        }
        if (line.len == 1)
          flaginheader = 0;
      } else
        if (!stralloc_cat(&text,&line)) die_nomem();
    }	/* got body */
    if (encin) {
      if (encin == 'B')
        decodeB(text.s,text.len,&line);
      else
        decodeQ(text.s,text.len,&line);
      if (!stralloc_copy(&text,&line)) die_nomem();
    }
    cp = text.s;
    cpafter = text.s + text.len;
    if (!stralloc_copys(&line,"\n>>>>> -------------------- >>>>>\n"))
			die_nomem();
    flaggoodfield = 0;
    flagdone = 0;
    while ((cpnext = cp + byte_chr(cp,cpafter-cp,'\n')) != cpafter) {
      i = byte_chr(cp,cpnext-cp,'%');
      if (i <= 5 && cpnext-cp-i >= 3) {
				/* max 5 "quote characters" and space for %%% */
        if (cp[i+1] == '%' && cp[i+2] == '%') {
          if (!flaggoodfield) {					/* Start tag */
            if (!stralloc_copyb(&quoted,cp,i)) die_nomem();	/* quote chars*/
            flaggoodfield = 1;
            cp = cpnext + 1;
            cpfirst = cp;
            continue;
          } else {						/* end tag */
            if (flagdone)	/* 0 no comment lines, 1 comment line */
              flagdone = 2;	/* 2 at least 1 comment line & end tag */
            break;
          }
        }
      }
      if (flaggoodfield) {
        cplast = cpnext - 1;
        if (*cplast == '\r')	/* CRLF -> '\n' for base64 encoding */
          *cplast = '\n';
        else
          ++cplast;
			/* NUL is now ok, so the test for it was removed */
        flagdone = 1;
        i = cplast - cp + 1;
        if (quoted.len && quoted.len <= i &&
		!str_diffn(cp,quoted.s,quoted.len)) {	/* quote chars */
          if (!stralloc_catb(&line,cp+quoted.len,i-quoted.len)) die_nomem();
        } else
          if (!stralloc_catb(&line,cp,i)) die_nomem();	/* no quote chars */
      }
      cp = cpnext + 1;
    }
    if (flagdone == 2) {
    if (!stralloc_cats(&line,"<<<<< -------------------- <<<<<\n")) die_nomem();
      code_qput(line.s,line.len);
    }
    if (flagcd == 'B') {
      encodeB("",0,&line,2);
      qmail_put(&qq,line.s,line.len);
    }
    if (flagmime) {
      hdr_boundary(0);
      hdr_ctype(CTYPE_MESSAGE);
    }
    qmail_puts(&qq,"\n");
    if (seek_begin(fd) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s));

    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
    if (qmail_copy(&qq,&sstext,-1) != 0)
      strerr_die2sys(111,FATAL,MSG1(ERR_READ,fnmsg.s));
    close(fd);

    if (flagmime)
      hdr_boundary(1);

    if (!stralloc_copy(&line,&outlocal)) die_nomem();
    if (!stralloc_cats(&line,"-return-@")) die_nomem();
    if (!stralloc_cat(&line,&outhost)) die_nomem();
    if (!stralloc_0(&line)) die_nomem();
    qmail_from(&qq,line.s);
    if (to.len)
      qmail_to(&qq,to.s);

    if (!stralloc_copys(&fnnew,"mod/rejected/")) die_nomem();
    if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem();
    if (!stralloc_0(&fnnew)) die_nomem();

/* this is strictly to track what happended to a message to give informative */
/* messages to the 2nd-nth moderator that acts on the same message. Since    */
/* this isn't vital we ignore errors. Also, it is no big ideal if unlinking  */
/* the old file fails. In the worst case it gets acted on again. If we issue */
/*  a temp error the reject will be redone, which is slightly worse.         */

    if (*(err = qmail_close(&qq)) == '\0') {
        fd = open_trunc(fnnew.s);
        if (fd != -1)
          close(fd);
        unlink(fnmsg.s);
        strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
        strerr_die2x(0,"ezmlm-moderate: info: qp ",strnum);
    } else
        strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);

  } else if (str_start(action,ACTION_ACCEPT)) {
        fd = open_read(fnmsg.s);
        if (fd == -1) {
          if (errno !=error_noent)
            strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fnmsg.s));
          else	/* shouldn't happen since we've got lock */
            strerr_die3x(100,FATAL,fnmsg.s,MSG(ERR_MOD_TIMEOUT));
	}

    substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
				/* read "Return-Path:" line */
    if (getln(&sstext,&line,&match,'\n') == -1 || !match)
      strerr_die2sys(111,FATAL,MSG(ERR_READ_INPUT));
    maketo();			/* extract SENDER to "to" */
    env_put2("SENDER",to.s);	/* set SENDER */
    if (seek_begin(fd) == -1)	/* rewind, since we read an entire buffer */
      strerr_die2sys(111,FATAL,MSG1(ERR_SEEK,fnmsg.s));

    if ((child = wrap_fork()) == 0) {
      close(0);
      dup(fd);	/* make fnmsg.s stdin */
      if (argc > opt + 1)
	wrap_execvp((const char **)argv + opt);
      else if (argc > opt)
        wrap_execsh(argv[opt]);
      else
        wrap_execbin("/ezmlm-send", &sendopt, dir);
    }
      /* parent */
      close(fd);
      wrap_exitcode(child);
      if (!stralloc_copys(&fnnew,"mod/accepted/")) die_nomem();

      if (!stralloc_cats(&fnnew,fnbase.s)) die_nomem();
      if (!stralloc_0(&fnnew)) die_nomem();
/* ignore errors */
      fd = open_trunc(fnnew.s);
      if (fd != -1)
        close(fd);
      unlink(fnmsg.s);
      _exit(0);
   }
}
Esempio n. 17
0
void
resp_recvfile(struct reqinfo *req)
{
    struct fsfd h;
    lx_s dest_dir  = {0},
         dest_file = {0},
         data      = {0};

    lx_s *value;
    char *endlen;
    int length;

    if (!OPT_WRITABL) {
        die_html(HTERR_FORBID, 0,
                "Write access forbidden",
                err_perm_denied);
    }

    fs_ready();

    fs_parseout(&dest_dir, &dest_file, &req->location);

    if (lx_check0(&dest_dir) ||
        lx_check0(&dest_file) ||
        lx_check0(&req->location)) die_nomem();

    log_debug(DEBUG_NOISE, dest_dir.s, "destination directory");
    log_debug(DEBUG_NOISE, dest_file.s, "destination file");

    value = blob_get(blob_header_recv, "content-length", 14);
    if (!value) {
        die_html(HTERR_NEEDLEN, 0,
                "POST request without Content-Length",
                "Content-Length header required");
    }

    lx_check0(value);
    length = strtoul(value->s, &endlen, 10);

    if (endlen == value->s || *endlen) {
        die_html(HTERR_NEEDLEN, 0,
                "POST request with invalid Content-Length",
                "Content-Length header required");
    }

    fs_chdir_write(dest_dir.s);

#if 0
    if (!chdir(dest_dir.s)) {
        if (opt_p.v_opt.opt_toggle) {
            fs_mkpath(dest_dir.s);
        } else {
            die_html(HTERR_NOTFOUND|ERRNO, req->location.s,
                    "chdir to target directory",
                    "Invalid target directory");
        }
    }

    fs_okay_write_dir();
#endif

    /* XXX: address if lx_check0 is modified to not increment len! */
    fs_open_file_write(&h, dest_file.s, dest_file.len-1);

    fs_slurp_gd2h(&h, gd_in, length);

    log_debug(DEBUG_NOISE, h.dest, "received file from feed");

    fs_close_file_write(&h);

    if (h.status & ST_INCOMPLETE) {
        die_log(0, dest_file.s, "short read from input stream", 0);
    }

    if (lx_striset(&data, "0", 1)) die_nomem();
    header_setstr(blob_header_send, "Content-Length", data.s, data.len);

    resp_sendprefix(req,
            (h.status & ST_CREATED) ? HTERR_OK_CREAT : HTERR_OK_NOCNT);
    resp_sendheaders(req, blob_header_send);

    lx_free(&dest_dir);
    lx_free(&dest_file);
    lx_free(&data);
}
Esempio n. 18
0
void tagmsg(const char *dir,		/* db base dir */
	    unsigned long msgnum,	/* number of this message */
	    const char *seed,		/* seed. NULL ok, but less entropy */
	    const char *action,	/* to make it certain the cookie differs from*/
				/* one used for a digest */
	    char *hashout,		/* calculated hash goes here */
	    unsigned long bodysize,
	    unsigned long chunk)
/* This routine creates a cookie from num,seed and the */
/* list key and returns that cookie in hashout. The use of sender/num and */
/* first char of action is used to make cookie differ between messages,   */
/* the key is the secret list key. The cookie will be inserted into       */
/* table_cookie where table and other data is taken from dir/sql. We log  */
/* arrival of the message (done=0). */
{
  PGresult *result;
  PGresult *result2; /* Need for dupicate check */
  const char *table;
  const char *ret;

  std_tagmsg(msgnum,seed,action,hashout);

  if ((ret = opensub(dir,0,&table))) {
    if (*ret) strerr_die2x(111,FATAL,ret);
    return;				/* no sql => success */

  } else {
    if (chunk >= 53L) chunk = 0L;	/* sanity */

	/* INSERT INTO table_cookie (msgnum,cookie) VALUES (num,cookie) */
	/* (we may have tried message before, but failed to complete, so */
	/* ER_DUP_ENTRY is ok) */
    if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem();
    if (!stralloc_cats(&line,table)) die_nomem();
    if (!stralloc_cats(&line,"_cookie (msgnum,cookie,bodysize,chunk) VALUES ("))
      die_nomem();
    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) die_nomem();
    if (!stralloc_cats(&line,",'")) die_nomem();
    if (!stralloc_catb(&line,hashout,COOKIE)) die_nomem();
    if (!stralloc_cats(&line,"',")) die_nomem();
    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,bodysize)))
      die_nomem();
    if (!stralloc_cats(&line,",")) die_nomem();
    if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,chunk))) die_nomem();
    if (!stralloc_cats(&line,")")) die_nomem();
    
    if (!stralloc_0(&line)) die_nomem();
    result = PQexec(pgsql,line.s);
    if (result == NULL)
      strerr_die2x(111,FATAL,PQerrorMessage(pgsql));
    if (PQresultStatus(result) != PGRES_COMMAND_OK) { /* Possible tuplicate */
      if (!stralloc_copys(&line,"SELECT msgnum FROM ")) die_nomem();
      if (!stralloc_cats(&line,table)) die_nomem();	  
      if (!stralloc_cats(&line,"_cookie WHERE msgnum = ")) die_nomem();
      if (!stralloc_catb(&line,strnum,fmt_ulong(strnum,msgnum))) 
	die_nomem();
      /* Query */
      if (!stralloc_0(&line)) die_nomem();
      result2 = PQexec(pgsql,line.s);
      if (result2 == NULL)
	strerr_die2x(111,FATAL,PQerrorMessage(pgsql));
      if (PQresultStatus(result2) != PGRES_TUPLES_OK)
	strerr_die2x(111,FATAL,PQresultErrorMessage(result2));
      /* No duplicate, return ERROR from first query */
      if (PQntuples(result2)<1) 
	strerr_die2x(111,FATAL,PQresultErrorMessage(result));
      PQclear(result2);
    }
    PQclear(result);

    if (! (ret = logmsg(dir,msgnum,0L,0L,1))) return;	/* log done=1*/
    if (*ret) strerr_die2x(111,FATAL,ret);
  }

  return;
}
Esempio n. 19
0
int main()
{
  buffer bin;
  buffer bout;
  struct prioq_elt pe;
  int fdoldmbox;
  int fdnewmbox;
  int fd;
  int match;
  int fdlock;

  umask(077);

  mbox = env_get("MAIL");
  if (!mbox) strerr_die2x(111,FATL,"MAIL not set");
  mboxtmp = env_get("MAILTMP");
  if (!mboxtmp) strerr_die2x(111,FATL,"MAILTMP not set");

  if (maildir_chdir() == -1)
    strerr_die1(111,FATAL,&maildir_chdir_err);
  maildir_clean(&filenames);
  if (maildir_scan(&pq,&filenames,1,1) == -1)
    strerr_die1(111,FATAL,&maildir_scan_err);

  if (!prioq_min(&pq,&pe)) _exit(0); /* nothing new */

  fdlock = open_append(mbox);
  if (fdlock == -1)
    strerr_die4sys(111,FATL,"unable to lock ",mbox,": ");
  if (lock_ex(fdlock) == -1)
    strerr_die4sys(111,FATL,"unable to lock ",mbox,": ");

  fdoldmbox = open_read(mbox);
  if (fdoldmbox == -1)
    strerr_die4sys(111,FATL,"unable to read ",mbox,": ");

  fdnewmbox = open_trunc(mboxtmp);
  if (fdnewmbox == -1)
    strerr_die4sys(111,FATL,"unable to create ",mboxtmp,": ");

  buffer_init(&bin,read,fdoldmbox,inbuf,sizeof(inbuf));
  buffer_init(&bout,write,fdnewmbox,outbuf,sizeof(outbuf));

  switch(buffer_copy(&bout,&bin))
  {
    case -2: strerr_die4sys(111,FATL,"unable to read ",mbox,": ");
    case -3: strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");
  }

  while (prioq_min(&pq,&pe))
  {
    prioq_delmin(&pq);
    if (!prioq_insert(&pq2,&pe)) die_nomem();

    fd = open_read(filenames.s + pe.id);
    if (fd == -1)
      strerr_die4sys(111,FATL,"unable to read $MAILDIR/",filenames.s + pe.id,": ");
    buffer_init(&bin,read,fd,inbuf,sizeof(inbuf));

    if (getln(&bin,&line,&match,'\n') != 0)
      strerr_die4sys(111,FATL,"unable to read $MAILDIR/",filenames.s + pe.id,": ");

    if (!stralloc_copys(&ufline,"From XXX ")) die_nomem();
    if (match)
      if (stralloc_starts(&line,"Return-Path: <"))
      {
        if (line.s[14] == '>')
    {
          if (!stralloc_copys(&ufline,"From MAILER-DAEMON ")) die_nomem();
    }
        else
        {
      int i;
         if (!stralloc_ready(&ufline,line.len)) die_nomem();
         if (!stralloc_copys(&ufline,"From ")) die_nomem();
      for (i = 14;i < line.len - 2;++i)
        if ((line.s[i] == ' ') || (line.s[i] == '\t'))
          ufline.s[ufline.len++] = '-';
        else {
          ufline.s[ufline.len++] = line.s[i];
          if (!stralloc_cats(&ufline," ")) die_nomem();
          }
        }
      }
    if (!stralloc_cats(&ufline,myctime(pe.dt))) die_nomem();
    if (buffer_put(&bout,ufline.s,ufline.len) == -1)
      strerr_die4sys(111,FATAL,"unable to write to ",mboxtmp,": ");

    while (match && line.len)
    {
      if (gfrom(line.s,line.len))
        if (buffer_puts(&bout,">") == -1)
          strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");
      if (buffer_put(&bout,line.s,line.len) == -1)
        strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");
      if (!match)
      {
        if (buffer_puts(&bout,"\n") == -1)
          strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");
        break;
      }
      if (getln(&bin,&line,&match,'\n') != 0)
        strerr_die4sys(111,FATL,"unable to read $MAILDIR/",filenames.s + pe.id,": ");
    }
    if (buffer_puts(&bout,"\n"))
      strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");

   close(fd);
  }

  if (buffer_flush(&bout) == -1)
    strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");
  if (fsync(fdnewmbox) == -1)
    strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");
  if (close(fdnewmbox) == -1) /* NFS dorks */
    strerr_die4sys(111,FATL,"unable to write to ",mboxtmp,": ");
  if (rename(mboxtmp,mbox) == -1)
    strerr_die6(111,FATL,"unable to move ",mboxtmp," to ",mbox,": ",&strerr_sys);

  while (prioq_min(&pq2,&pe))
  {
    prioq_delmin(&pq2);
    if (unlink(filenames.s + pe.id) == -1)
      strerr_warn4(WARNING,"$MAILDIR/",filenames.s + pe.id," will be delivered twice; unable to unlink: ",&strerr_sys);
  }

  return(0);
}
Esempio n. 20
0
void connection_accept(int c) {
  int ac;
  const char **run;
  const char *args[4];
  char *ip =(char*)&socka.sin_addr;

  remote_ip[ipsvd_fmt_ip(remote_ip, ip)] =0;
  if (verbose) {
    out(INFO); out("pid ");
    bufnum[fmt_ulong(bufnum, getpid())] =0;
    out(bufnum); out(" from "); outfix(remote_ip); flush("\n");
  }
  remote_port[ipsvd_fmt_port(remote_port, (char*)&socka.sin_port)] =0;
  if (lookuphost) {
    if (ipsvd_hostname(&remote_hostname, ip, paranoid) == -1)
      warn2("unable to look up hostname", remote_ip);
    if (! stralloc_0(&remote_hostname)) drop_nomem();
  }
  socka_size =sizeof(socka);
  if (getsockname(c, (struct sockaddr*)&socka, &socka_size) == -1)
    drop("unable to get local address");
  if (! local_hostname.len) {
    if (dns_name4(&local_hostname, (char*)&socka.sin_addr) == -1)
      drop("unable to look up local hostname");
    if (! stralloc_0(&local_hostname)) die_nomem();
  }
  local_ip[ipsvd_fmt_ip(local_ip, (char*)&socka.sin_addr)] =0;

  if (ucspi) ucspi_env();
  if (instructs) {
    ac =ipsvd_check(iscdb, &inst, &match, (char*)instructs,
                    remote_ip, remote_hostname.s, timeout);
    if (ac == -1) drop2("unable to check inst", remote_ip);
    if (ac == IPSVD_ERR) drop2("unable to read", (char*)instructs);
  }
  else ac =IPSVD_DEFAULT;

  if (phccmax) {
    if (phcc > phccmax) {
      ac =IPSVD_DENY;
      if (phccmsg) {
        ndelay_on(c);
        if (write(c, phccmsg, str_len(phccmsg)) == -1)
          warn("unable to write concurrency message");
      }
    }
    if (verbose) {
      bufnum[fmt_ulong(bufnum, getpid())] =0;
      out(INFO); out("concurrency "); out(bufnum); out(" ");
      outfix(remote_ip); out(" ");
      bufnum[fmt_ulong(bufnum, phcc)] =0;
      out(bufnum); out("/");
      bufnum[fmt_ulong(bufnum, phccmax)] =0;
      out(bufnum); out("\n");
    }
  }
  if (verbose) {
    out(INFO);
    switch(ac) {
    case IPSVD_DENY: out("deny "); break;
    case IPSVD_DEFAULT: case IPSVD_INSTRUCT: out("start "); break;
    case IPSVD_EXEC: out("exec "); break;
    }
    bufnum[fmt_ulong(bufnum, getpid())] =0;
    out(bufnum); out(" ");
    outfix(local_hostname.s); out(":"); out(local_ip);
    out(" :"); outfix(remote_hostname.s); out(":");
    outfix(remote_ip); out(":"); outfix(remote_port);
    if (instructs) {
      out(" ");
      if (iscdb) {
        out((char*)instructs); out("/");
      }
      outfix(match.s);
      if(inst.s && inst.len && (verbose > 1)) {
        out(": "); outinst(&inst);
      }
    }
    flush("\n");
  }

  if (ac == IPSVD_DENY) {
    close(c);
    _exit(100);
  }
  if (ac == IPSVD_EXEC) {
    args[0] ="/bin/sh"; args[1] ="-c"; args[2] =inst.s; args[3] =0;
    run =args;
  }
  else run =prog;
  if ((fd_move(0, c) == -1) || (fd_copy(1, 0) == -1))
    drop("unable to set filedescriptor");
  sig_uncatch(sig_term);
  sig_uncatch(sig_pipe);
  sig_uncatch(sig_child);
  sig_unblock(sig_child);
#ifdef SSLSVD
  pid =getpid();
  id[fmt_ulong(id, pid)] =0;
  ssl_io(0, run);
#else
  pathexec(run);
#endif

  drop2("unable to run", (char *)*prog);
}
Esempio n. 21
0
void msgout(unsigned long msg,char format)
/* Outputs message (everything that's needed per message) */
{
  int fd;
  unsigned int len;

    if (!stralloc_copys(&fn,"archive/")) die_nomem();

    len = fmt_ulong(strnum, msg / 100);
    if (!stralloc_catb(&fn,strnum,len)) die_nomem();
    if (!stralloc_cats(&fn,"/")) die_nomem();
    len = fmt_uint0(strnum, (unsigned int) (msg % 100),2);
    if (!stralloc_catb(&fn,strnum,len)) die_nomem();
    if (!stralloc_0(&fn)) die_nomem();

    switch(format) {
      case MIME:
      case VIRGIN:
      case NATIVE:
      case MIXED:
	fd = open_read(fn.s);
	if (fd == -1) {
	  if (errno != error_noent)
	    strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fn.s));
          else
            mime_getbad(msg);
        } else if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100))) {
	  close(fd);
          mime_getbad(msg);
        } else {
	  hdr_boundary(0);
	  hdr_ctype(CTYPE_MESSAGE);
          qmail_puts(&qq,"Content-Disposition: inline; filename=\"");
	  qmail_put(&qq,listname.s,listname.len);
	  qmail_puts(&qq,"_");
	  qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
	  qmail_puts(&qq,".ezm\"\n\n");
          copymsg(fd,format);
	  close(fd);
        }
	break;
      case RFC1153:
	fd = open_read(fn.s);
	if (fd == -1) {
	  if (errno != error_noent)
	    strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fn.s));
	  else {
	    qmail_puts(&qq,"\n== ");
	    qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
	    qmail_puts(&qq," ==\n\n");
	    copy(&qq,"text/get-bad",flagcd);
          }
        } else {
          if (fstat(fd,&st) == -1 || (!(st.st_mode & 0100))) {
	    close(fd);
	    qmail_puts(&qq,"\n== ");
	    qmail_put(&qq,strnum,fmt_ulong(strnum,msg));
	    qmail_puts(&qq," ==\n\n");
	    copy(&qq,"text/get-bad",flagcd);
	  } else {
	    copymsg(fd,format);
	    close(fd);
          }
	}
	qmail_puts(&qq,"\n------------------------------\n\n");
	break;
      default:
        strerr_die2x(100,FATAL,"Program error: Unrecognized format in msgout");
        break;
    }
}
Esempio n. 22
0
int main(int argc, char **argv) {
  int opt;
  char *user =0;
  char *host;
  unsigned long port;
  int pid;
  int s;
  int conn;
  int delim;

  progname =*argv;
  phccmax =0;

#ifdef SSLSVD
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) {
#else
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vV")) != opteof) {
#endif
    switch(opt) {
    case 'c': scan_ulong(optarg, &cmax); if (cmax < 1) usage(); break;
    case 'C':
      delim =scan_ulong(optarg, &phccmax);
      if (phccmax < 1) usage();
      if (optarg[delim] == ':') {
        if (ipsvd_fmt_msg(&msg, optarg +delim +1) == -1) die_nomem();
        if (! stralloc_0(&msg)) die_nomem();
        phccmsg =msg.s;
      }
      break;
    case 'i': if (instructs) usage(); instructs =optarg; break;
    case 'x': if (instructs) usage(); instructs =optarg; iscdb =1; break;
    case 'u': user =(char*)optarg; break;
    case 'l':
      if (! stralloc_copys(&local_hostname, optarg)) die_nomem();
      if (! stralloc_0(&local_hostname)) die_nomem();
      break;
    case 'E': ucspi =0; break;
    case 'b': scan_ulong(optarg, &backlog); break;
    case 'h': lookuphost =1; break;
    case 'p': lookuphost =1; paranoid =1; break;
    case 't': scan_ulong(optarg, &timeout); break;
    case 'v': ++verbose; break;
#ifdef SSLSVD
    case 'U': ssluser =(char*)optarg; break;
    case '/': root =(char*)optarg; break;
    case 'Z': cert =(char*)optarg; break;
    case 'K': key =(char*)optarg; break;
#endif
    case 'V': strerr_warn1(VERSION, 0);
    case '?': usage();
    }
  }
  argv +=optind;

  if (! argv || ! *argv) usage();
  host =*argv++;
  if (! argv || ! *argv) usage();
  local_port =*argv++;
  if (! argv || ! *argv) usage();
  prog =(const char **)argv;
  if (phccmax > cmax) phccmax =cmax;

  if (user)
    if (! uidgids_get(&ugid, user)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", user, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", user);
    }
#ifdef SSLSVD
  svuser =user;
  client =0;
  if ((getuid() == 0) && (! ssluser))
    strerr_die2x(100, FATAL, "-U ssluser must be set when running as root");
  if (ssluser)
    if (! uidgids_get(&sslugid, ssluser)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", ssluser, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", ssluser);
    }
  if (! cert) cert ="./cert.pem";
  if (! key) key =cert;
  if (matrixSslOpen() < 0) fatal("unable to initialize ssl");
  if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
    if (client) fatal("unable to read cert, key, or ca file");
    fatal("unable to read cert or key file");
  }
  if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
    strerr_die2x(111, FATAL, "unable to create ssl session");
#endif

  dns_random_init(seed);
  sig_block(sig_child);
  sig_catch(sig_child, sig_child_handler);
  sig_catch(sig_term, sig_term_handler);
  sig_ignore(sig_pipe);

  if (phccmax) if (ipsvd_phcc_init(cmax) == -1) die_nomem();

  if (str_equal(host, "")) host ="0.0.0.0";
  if (str_equal(host, "0")) host ="0.0.0.0";

  if (! ipsvd_scan_port(local_port, "tcp", &port))
    strerr_die3x(100, FATAL, "unknown port number or name: ", local_port);

  if (! stralloc_copys(&sa, host)) die_nomem();
  if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4))
    if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1)
      fatal2("unable to look up ip address", host);
  if (ips.len < 4)
    strerr_die3x(100, FATAL, "unable to look up ip address: ", host);
  ips.len =4;
  if (! stralloc_0(&ips)) die_nomem();
  local_ip[ipsvd_fmt_ip(local_ip, ips.s)] =0;

  if (! lookuphost) {
    if (! stralloc_copys(&remote_hostname, "")) die_nomem();
    if (! stralloc_0(&remote_hostname)) die_nomem();
  }

  if ((s =socket_tcp()) == -1) fatal("unable to create socket");
  if (socket_bind4_reuse(s, ips.s, port) == -1)
    fatal("unable to bind socket");
  if (listen(s, backlog) == -1) fatal("unable to listen");
  ndelay_off(s);

#ifdef SSLSVD
#else
  if (user) {
    /* drop permissions */
    if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to set groups");
    if (setgid(*ugid.gid) == -1) fatal("unable to set gid");
    if (prot_uid(ugid.uid) == -1) fatal("unable to set uid");
  }
#endif
  close(0);

  if (verbose) {
    out(INFO); out("listening on "); outfix(local_ip); out(":");
    outfix(local_port);
#ifdef SSLSVD
#else
    if (user) {
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.uid)] =0;
      out(", uid "); out(bufnum);
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.gid)] =0;
      out(", gid "); out(bufnum);
    }
#endif
    flush(", starting.\n");
  }
  for (;;) {
    while (cnum >= cmax) sig_pause();
    socka_size =sizeof(socka);

    sig_unblock(sig_child);
    conn =accept(s, (struct sockaddr *)&socka, &socka_size);
    sig_block(sig_child);

    if (conn == -1) {
      if (errno != error_intr) warn("unable to accept connection");
      continue;
    }
    cnum++;

    if (verbose) connection_status();
    if (phccmax) phcc =ipsvd_phcc_add((char*)&socka.sin_addr);
    if ((pid =fork()) == -1) {
      warn2("drop connection", "unable to fork");
      close(conn);
      continue;
    }
    if (pid == 0) {
      /* child */
      close(s);
#ifdef SSLSVD
      if (*progname) *progname ='\\';
#endif
      connection_accept(conn);
    }
    if (phccmax) ipsvd_phcc_setpid(pid);
    close(conn);
  }
  _exit(0);
}
Esempio n. 23
0
void main(int argc,char **argv)
{
  char *def;
  char *local;
  const char *action = "";
  char *psz;
  const char *err;
  int fd;
  unsigned int i,j;
  int flagremote;
  int match;
  int goodexit = 0;			/* exit code for normal exit */
					/* in manager this will be set to 0 */
  unsigned long from,u,to,issue,prevmax;
  unsigned long mno = 0;
  unsigned long chunk;
  unsigned long subs = 0;
  unsigned int pos,pos1;
  unsigned int len;
  int opt;
  char outformat = 0;
  msgentry *msgtable;
  subentry *subtable;
  authentry *authtable;
  dateentry *datetable;
  struct datetime dt;
  char date[DATE822FMT];

  (void) umask(022);
  sig_pipeignore();
  when = now();
  datetime_tai(&dt,when);

  opt = getconfopt(argc,argv,options,1,0);

  initsub(0);
  if (flagformat != 0)
    if (FORMATS[str_chr(FORMATS,flagformat[0])])
      outformat = flagformat[0];
  if (outformat == 0) {
    outformat =
      (getconf_line(&line,"digformat",0)
       && FORMATS[str_chr(FORMATS,line.s[0])])
      ? line.s[0]
      : DEFAULT_FORMAT;
  }

  /* code to activate digest (-digest-code)*/
  if ((digestcode = argv[opt]) == 0) {
    if (getconf_line(&digestcodefile,"digestcode",0)
	&& digestcodefile.len > 0) {
      if (!stralloc_0(&digestcodefile)) die_nomem();
      digestcode = digestcodefile.s;
    }
  }
  /* ignore any extra args */

  if (!stralloc_copy(&subject,&outlocal)) die_nomem();	/* for subjects */
  if (!stralloc_copy(&listname,&outlocal)) die_nomem();	/* for content disp */

  local = env_get("LOCAL");
  def = env_get("DEFAULT");
  sender = get_sender();
  if (local && *local) {	/* in editor local = outlocal */
    if (!sender) strerr_die2x(100,FATAL,MSG(ERR_NOSENDER));
    if (!*sender)
      strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));
    if (str_equal(sender,"#@[]"))
      strerr_die2x(100,FATAL,MSG(ERR_BOUNCE));
    if (!sender[str_chr(sender,'@')])
      strerr_die2x(100,FATAL,MSG(ERR_ANONYMOUS));
    if (def) {
      if (*def) {
	action = def;
	goodexit = 99;
      } else
	_exit(0);		/* list-@host should do -help from manager */
    } else {			/* editor */
      act = AC_DIGEST;		/* on list-@host ! */
      flageditor = 1;		/* to avoid Mailing-list error on sublists */
				/* when running out of dir/editor. */
    }
    if (case_starts(action,"dig")) {
      action += 3;
      if (action[0] == '-' || action [0] == '.') {
        action++;
	if (!digestcode)
            strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE));
        len = str_len(digestcode);
        if (len <= str_len(action) && case_startb(action,len,digestcode)) {
          if (FORMATS[str_chr(FORMATS,*(action+len))])
            outformat = *(action+len);
          act = AC_DIGEST;
        } else
          strerr_die2x(100,FATAL,MSG(ERR_BAD_DIGCODE));
      }
    }
  } else			/* Command line operation */
    act = AC_DIGEST;

	/* Things we deal with. If anything else just die with success!   */
	/* At the moment this is -index, -thread, and -get.               */
	/* If flagdo = 0 we only service -dig commands. This is to support*/
	/* "secret" lists that are still archived and digested. -c on     */
	/* cmd line. */

  if (act == AC_NONE) {
    if (case_equals(action,ACTION_DIGEST)) {
      act = AC_GET;		/* list-digest@ => msg since last digest */
      action = ACTION_GET;
    } else if (case_starts(action,ACTION_GET) || case_starts(action,ALT_GET))
      act = AC_GET;
    else if (case_starts(action,ACTION_INDEX) || case_starts(action,ALT_INDEX))
      act = AC_INDEX;
    else if (case_starts(action,ACTION_THREAD) ||
	 case_starts(action,ALT_THREAD))
      act = AC_THREAD;
  }
  if (act == AC_NONE)			/* not for us. Pass the buck. */
    _exit(0);
  if (act != AC_INDEX) {		/* need to do header processing */
    if(!getconf(&digheaders,"digheaders",0)) {
      if(!stralloc_copys(&digheaders,digsz)) die_nomem();
      if (!stralloc_0(&digheaders)) die_nomem();
      psz = digheaders.s;
      while (*psz) {
        if (*psz == '\\') *psz = '\0';
        ++psz;
      }
    }
    if (!constmap_init(&digheadersmap,digheaders.s,digheaders.len,0))
	die_nomem();
  }
  if (act != AC_DIGEST) {
    if (!flagdo)			/* only do digests */
      strerr_die2x(100,FATAL,MSG(ERR_NOCMD));
    if (flagpublic < 0)
      flagpublic = !getconf_isset("modgetonly") && getconf_isset("public");
    if (!flagpublic) {
		/* This all to take care of non-public lists. They should*/
		/* still do digests, but do other things only for        */
		/* moderators that have remote access. Since this is rare*/
		/* efforts have been made to keep everything that's not  */
		/* needed elsewhere in here.                   */
      getconf_line(&moddir,"modsub",0);
      flagremote = getconf_line(&line,"remote",0);
      if (!flagremote)
        strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC));
      if (!moddir.len) {
        if (line.len) {
          if (!stralloc_copy(&moddir,&line)) die_nomem();
        } else {
          if (!stralloc_copys(&moddir,"mod")) die_nomem();
        }
      }
      if (!stralloc_0(&moddir)) die_nomem();
      ismod = issub(moddir.s,sender,&mod);
      if (!ismod)			/* sender = moderator? */
        strerr_die2x(100,FATAL,MSG(ERR_NOT_PUBLIC));
    }
  }

  if (act == AC_DIGEST) {
    workdir = "digest";
    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();
    if (getconf_line(&line,"chunk",0)) {
      if (!stralloc_0(&line)) die_nomem();
      (void) scan_ulong(line.s,&chunk);		/* same chunk as main list */
      if (chunk == 0)				/* limit range to 1-53 */
	chunk = 1L;
      else if (chunk > 52)
	chunk = 52L;
    } else {
      chunk = 0L;
    }
  } else
    workdir = ".";


  if (!flagarchived)
    strerr_die2x(100,FATAL,MSG(ERR_NOT_ARCHIVED));

  if (qmail_open(&qq) == -1)
    strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));

  set_cpnum("");	/* default for <#n#> replacement */

  switch (act) {

  case AC_DIGEST:

/* -dig{.|-}'digestcode'[f] returns an rfc1153 digest                        */
/* of messages from the archive. Messages                                    */
/* dignum+1 through the last message received by the list are processed and  */
/* dignum is updated to the last message processed. digissue is advanced.    */

    get_num();				/* max = last successful message */
    to = max;
    lockup();			/* another digest could corrupt dignum */
				/* but will be saved only if flagdigrange==0 */
    if(getconf_line(&num,"dignum",0)) {
      if(!stralloc_0(&num)) die_nomem();
      pos = scan_ulong(num.s,&prevmax);
      if (num.s[pos] == ':') pos++;
      pos += 1 + scan_ulong(num.s+pos,&cumsize);	/* last cumsize */
      if (num.s[pos] == ':') pos++;
      scan_ulong(num.s+pos,&digwhen);			/* last reg dig */
    } else {
      prevmax = 0L;
      cumsize = 0L;
      digwhen = 0L;
    }
    mno = prevmax + 1L;
    if(!max || mno > max)	/* if a digest-list is "sending" the request, */
				/* don't make noise: errors go to postmaster!*/
      strerr_die2x(goodexit,FATAL,MSG(ERR_EMPTY_DIGEST));
    szmsgnum[fmt_ulong(szmsgnum,mno)] = '\0';
    set_cpnum(szmsgnum);	/* for copy */
				/* prepare subject to get entropy for tagmsg*/
    if (!stralloc_cats(&subject," Digest ")) die_nomem();
    if (!stralloc_catb(&subject,date,date822fmt(date,&dt)-1))
          die_nomem();		/* skip trailing in date '\n' */
    if (!stralloc_cats(&subject," Issue ")) die_nomem();
    if (getconf_line(&num,"digissue",0)) {
      if(!stralloc_0(&num)) die_nomem();
      scan_ulong(num.s,&issue);
      issue++;
    } else {
      issue = 1;
    }
    if (!stralloc_catb(&subject,strnum,fmt_ulong(strnum,issue)))
      die_nomem();
					/* use the subject as entropy */
    if (!stralloc_copy(&line,&subject)) die_nomem();
    if (!stralloc_0(&line)) die_nomem();

    if (!stralloc_ready(&seed,HASHLEN+1)) die_nomem();
    seed.len = HASHLEN + 1;
    seed.s[HASHLEN] = '\0';
    makehash(line.s,line.len,seed.s);
    if (chunk) {			/* only if slaves are used */
      qmail_puts(&qq,"Ezauth: ");
      qmail_put(&qq,seed.s,HASHLEN);
      qmail_puts(&qq,"\n");
    }

    doheaders();
    qmail_puts(&qq,"To: ");
    if (!quote(&quoted,&listname)) die_nomem();
    qmail_put(&qq,quoted.s,quoted.len);
    qmail_puts(&qq,"@");
    qmail_put(&qq,outhost.s,outhost.len);
    qmail_puts(&qq,"\n");
    if (flagindexed && (outformat != NATIVE))
      idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,
	mno,to,max,flaglocked);
    else
      idx_mklist(&msgtable,&subtable,&authtable,mno,to);
    digest(msgtable,subtable,authtable,mno,to,&subject,AC_DIGEST,outformat);

    write_ulong(issue,0L,0L,"digissue","digissuen");
    write_ulong(max,cumsizen, (unsigned long) when,"dignum","dignumn");
    break;

  case AC_GET:

/* -get[-|\.][[num].num2] copies archive num-num2. num & num2 are adjusted   */
/* to be > 0 and <= last message, to num2 >= num and to num2-num <= MAXGET.  */

    zapnonsub(ACTION_GET);		/* restrict to subs if requested */
    tosender();
				/* for rfc1153 */
    if (!stralloc_cats(&subject," Digest of: ")) die_nomem();
    if (!stralloc_cats(&subject,action)) die_nomem();

    to = 0;
    pos = str_len(ACTION_GET);
    if (!case_starts(action,ACTION_GET))
      pos = str_len(ALT_GET);
    if (FORMATS[str_chr(FORMATS,action[pos])]) {
       outformat = action[pos];
       ++pos;
    }
					/* optional - or . after '-get' */
    if (action[pos] == '-' || action[pos] == '.') pos++;
    get_num();				/* max = last successful message */
					/* accept any separator. It may be  */
					/* the terminal '\n', but then      */
					/* scan will = 0 on the \0 so should*/
					/* be safe                          */
    if (!max)
      strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST));
    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
    set_cpnum(szmsgnum);	/* for copy this is the latest message arch'd*/
    doheaders();
    if(action[pos += scan_ulong(action + pos,&u)])
      scan_ulong(action + pos + 1, &to);
    if (u == 0 && to == 0) {		/* default: messages since last */
					/* digest, or last MAXGET if too many */
      to= max;
      u = dignum();
      if (u == 0) {		/* no digest => last up to HISTGET msgs */
	to = max;
	if (max > HISTGET) u = max - HISTGET; else u = 1;
      }
      if (to - u >= MAXGET) u = to - MAXGET + 1;	/* max MAXGET */
    } else if (u > max) {
      if (to) {			/* -get.999999_x returns 30 and msg since last*/
	to = max;		/* digest 30*/
        u = dignum();
	if (u > HISTGET) u -= HISTGET; else u = 1;
        if (to - u >= MAXGET) u = to - MAXGET + 1;
      } else
	u = max;
    }
    if (u == 0) u = 1;			/* -get.5 => 1-5 */
    if (to < u) to = u;			/* -get23_2 => 23 */
    if (to >= u + MAXGET) to = u + MAXGET - 1;
					/* no more than MAXGET at a time */
    if (to > max) to = max;
    if (flagindexed && (outformat != NATIVE))	/* fake out threading */
      idx_mkthreads(&msgtable,&subtable,&authtable,&datetable,
	u,to,max,0);
    else
      idx_mklist(&msgtable,&subtable,&authtable,u,to);
    digest(msgtable,subtable,authtable,u,to,&subject,AC_GET,outformat);
    break;

  case AC_INDEX:

/* -index[f][#|-|\.][[num][.num2] Show subject index for messages num-num2 in*/
/* sets of 100.                                                              */
/* Default last 2 sets. num and num2 are made reasonable as for get. num2 is */
/* limited to num+MAXINDEX to limit the amount of data sent.                 */

    if (!flagindexed)
      strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED));
    zapnonsub(ACTION_INDEX);	/* restrict to subs if requested */
    to = 0;
    pos = str_len(ACTION_INDEX);
    if (!case_starts(action,ACTION_INDEX))
      pos = str_len(ALT_INDEX);
    if (FORMATS[str_chr(FORMATS,action[pos])]) {
       outformat = action[pos];		/* ignored, but be nice ... */
       ++pos;
    }
    get_num();				/* max = last successful message */
    if (!max)
      strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST));
    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
    set_cpnum(szmsgnum);	/* for copy this is the latest message arch'd*/

    doheaders();
    tosender();
    if (!stralloc_cats(&subject," Result of: ")) die_nomem();
    if (!stralloc_cats(&subject,action)) die_nomem();
    presub(1,1,&subject,AC_INDEX,outformat);

    if (action[pos] == '-' || action[pos] == '.') pos++;
    if(action[pos += scan_ulong(action + pos,&u)])
      scan_ulong(action + pos + 1, &to);

    if (u == 0 && to == 0) { to = max; u = max - 100; }
    if (u <= 0) u = 1;
    if (u > max) u = max;
    if (to < u) to = u;
    if (to > u + MAXINDEX) to = u+MAXINDEX;	/* max MAXINDEX index files */
    if (to > max) to = max;
    u /= 100;
    to /= 100;
    while (u <= to) {
      if (!stralloc_copys(&fn,"archive/")) die_nomem();
      if (!stralloc_catb(&fn,strnum,fmt_ulong(strnum,u))) die_nomem();
      if (!stralloc_cats(&fn,"/index")) die_nomem();
      if (!stralloc_0(&fn)) die_nomem();

      if (u == max/100)	/* lock if last index file in archive */
        lockup();

      fd = open_read(fn.s);
      if (fd == -1)
        if (errno != error_noent)
          strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,fn.s));
        else
          code_qputs(MSG(TXT_NOINDEX));
      else {
        substdio_fdbuf(&sstext,read,fd,textbuf,sizeof(textbuf));
        for (;;) {
          if (getln(&sstext,&line,&match,'\n') == -1)
            strerr_die2sys(111,FATAL,MSG1(ERR_READ,fn.s));
          if (match) {
            if (line.s[0] != '\t') {	/* subject line */
              pos = byte_chr(line.s,line.len,' ');
	      pos1 = 0;
	      if (pos && pos != line.len && line.s[pos - 1] == ':')
                pos1 = pos + HASHLEN + 1;	/* after hash */
              if (pos1 >= line.len) {	/* bad! */
                pos = 0;
                pos1 = 0;		/* output as is */
              }
              if (!stralloc_copyb(&line2,line.s,pos)) die_nomem();
              if (!stralloc_catb(&line2,line.s+pos1,line.len-pos1)) die_nomem();
            } else {
	      pos = byte_chr(line.s,line.len,';');
	      if (pos + HASHLEN + 1 < line.len && pos > 15 &&
				line.s[pos + 1] != ' ') {
		  if (!stralloc_copyb(&line2,line.s,pos - 15)) die_nomem();
		  pos++;
		  if (!stralloc_catb(&line2,line.s + pos + HASHLEN,
			line.len - pos - HASHLEN)) die_nomem();
	      } else			/* old format - no author hash */
                if (!stralloc_copyb(&line2,line.s,line.len)) die_nomem();
	    }
            code_qput(line2.s,line2.len);
          } else
            break;
        }
        close(fd);
      }

      if (u == max/100)	/* unlock if last index in archive file */
        unlock();

      u++;
    }
    normal_bottom(outformat);
    postmsg(outformat);
    break;

  case AC_THREAD:

/* -thread[f][-|.]num returns messages with subject matching message        */
/* 'num' in the subject index. If 'num' is not in[1..last_message] an error */
/* message is returned.                                                     */

    if (!flagindexed)
      strerr_die2x(100,FATAL,MSG(ERR_NOT_INDEXED));

    zapnonsub(ACTION_THREAD);		/* restrict to subs if requested*/

    get_num();				/* max = last successful message */
    if (!max)
      strerr_die2x(100,FATAL,MSG(ERR_EMPTY_LIST));
    szmsgnum[fmt_ulong(szmsgnum,max)] = '\0';
    set_cpnum(szmsgnum);	/* for copy this is the latest message arch'd*/

    doheaders();
    tosender();
				/* for rfc1153 */
    if (!stralloc_cats(&subject," Digest of: ")) die_nomem();
    if (!stralloc_cats(&subject,action)) die_nomem();

    to = 0;
    pos = str_len(ACTION_THREAD);
    if (!case_starts(action,ACTION_THREAD))
      pos = str_len(ALT_THREAD);
    if (FORMATS[str_chr(FORMATS,action[pos])]) {
       outformat = action[pos];
       ++pos;
    }
    if (action[pos] == '-' || action[pos] == '.') pos++;
    if(action[pos += scan_ulong(action + pos,&u)])
      scan_ulong(action + pos + 1, &to);

    if(u == 0 || u > max) {
      hdr_add2("Subject: ",subject.s,subject.len);
      qmail_puts(&qq,"\n");
      copy(&qq,"text/get-bad",flagcd);
    } else {	/* limit range to at most u-THREAD_BEFORE to u+THREAD_AFTER */
      if (u > THREAD_BEFORE)
        from = u-THREAD_BEFORE;
      else
        from = 1L;
      if (u + THREAD_AFTER > max) {
        idx_mkthread(&msgtable,&subtable,&authtable,from,max,u,max,0);
        digest(msgtable,subtable,authtable,from,max,&subject,
		AC_THREAD,outformat);
      } else {
        idx_mkthread(&msgtable,&subtable,&authtable,
		from,u+THREAD_AFTER,u,max,0);
        digest(msgtable,subtable,authtable,from,u+THREAD_AFTER,
			&subject,AC_THREAD,outformat);
      }
    }
    break;

  default:
	/* This happens if the initial check at the beginning of 'main'    */
	/* matches something that isn't matched here. Conversely, just     */
	/* adding an action here is not enough - it has to be added to the */
	/* initial check as well.                                          */

    strerr_die2x(100,FATAL,
		 "Program error: I'm supposed to deal with this but I didn't");
  }

  if (!stralloc_copy(&line,&outlocal)) die_nomem();
  if (act == AC_DIGEST) {
    if (chunk) {
      if (!stralloc_cats(&line,"-return-g-")) die_nomem();
    } else
      if (!stralloc_cats(&line,"-return-")) die_nomem();
    strnum[fmt_ulong(strnum,mno)] = '\0';
    if (!stralloc_cats(&line,strnum)) die_nomem();
    if (!stralloc_cats(&line,"-@")) die_nomem();

    if (!stralloc_cat(&line,&outhost)) die_nomem();
    if (!stralloc_cats(&line,"-@[]")) die_nomem();
  } else {
    if (!stralloc_cats(&line,"-return-@")) die_nomem();
    if (!stralloc_cat(&line,&outhost)) die_nomem();
  }
  if (!stralloc_0(&line)) die_nomem();

  qmail_from(&qq,line.s);
  if (act == AC_DIGEST) {	 /* Do recipients */
    tagmsg(mno,seed.s,"d",hashout,qq.msgbytes,chunk);
    if (chunk) {
      if (!stralloc_copys(&line,"T")) die_nomem();
      if (!stralloc_cat(&line,&outlocal)) die_nomem();
      if (!stralloc_cats(&line,"-s-d-")) die_nomem();
      if (!stralloc_catb(&line,hashout,COOKIE)) die_nomem();
      if (!stralloc_cats(&line,"-")) die_nomem();
      if (!stralloc_cats(&line,strnum)) die_nomem();
      if (!stralloc_cats(&line,"-")) die_nomem();
      if (!stralloc_copys(&line2,"@")) die_nomem();
      if (!stralloc_cat(&line2,&outhost)) die_nomem();
      if (!stralloc_0(&line2)) die_nomem();
      j = 0;
      for (i = 0; i <= 52; i += chunk) {		/* To slaves */
        qmail_put(&qq,line.s,line.len);
        schar[0] = '0' + i / 10;
        schar[1] = '0' + (i % 10);
        qmail_put(&qq,schar,3);
        j += (chunk - 1);
        if (j > 52) j = 52;
        schar[0] = '0' + j / 10;
        schar[1] = '0' + (j % 10);
        qmail_put(&qq,schar,2);
        qmail_put(&qq,line2.s,line2.len);
      }
    } else
      subs = putsubs(workdir,0L,52L,&subto);
  } else {			/* if local is set, sender is checked */
    if (ismod)
      qmail_to(&qq,mod.s);
    else
      qmail_to(&qq,sender);
  }

  if (*(err = qmail_close(&qq)) == '\0') {	/* Done. Skip rest. */
    if (act == AC_DIGEST) {
      if (chunk)
	(void) logmsg(mno,0L,0L,2);
      else
        (void) logmsg(mno,0L,subs,4);
    }
    closesub();			/* close db connection */
    unlock();			/* NOP if nothing locked */
    strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
    strerr_die2x(goodexit,"ezmlm-get: info: qp ",strnum);
  } else {			/* failed. Reset last msg & issue for digest */
    if(act == AC_DIGEST) {
      issue--;
      write_ulong(issue,0L,0L,"digissue","digissuen");
      write_ulong(prevmax,cumsize,(unsigned long) digwhen,"dignum","dignumn");
    }
    unlock();			/* NOP if nothing locked */
    strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);
  }
}
Esempio n. 24
0
void
die_html(int hterr, char *arg_info,
        char *log_info, char *user_comment)
{
    /* ignore all user-supplied data on error, including user-supplied req.
     * XXX: breaks spec?
     */
    struct reqinfo req = {
        {0}, {0}, 1, 0
    };

    lx_s body = {0},
         data = {0};

    int err = (hterr & ERRNO) ? errno : 0;
    int hterridx = hterr & (~ERRNO);

    sendfmt(f_fatal, arg_info, log_info, err ? strerror(err) : 0);

    if (stage & SENT_PREFIX) {
        /* oh, well.  Prefix already sent; may as well not supply user info
         * now, since we'd just corrupt the data already given.
         */
        goto JUSTDIE;
    }

    header_reinit(&blob_header_send);
    header_set_default(hterridx);

    /* RFC-compliance means that we gather this regardless of whether we
     * send the data.  I guess i care.
     */
    if (lx_stradd(&body,
                "<html>\r\n"
                "  <head>\r\n"
                "    <title>")) die_nomem();
    if (lx_stradd(&body, user_comment)) die_nomem();
    if (lx_stradd(&body, "</title>\r\n"
                "  </head>\r\n"
                "  <body>")) die_nomem();
    if (lx_stradd(&body, user_comment)) die_nomem();
    if (lx_stradd(&body, "</body>\r\n"
                "</html>\r\n")) die_nomem();

    if (lx_strset(&data, "text/html")) die_nomem();
    header_setstr(blob_header_send, "Content-Type", data.s, data.len);

    data.len = 0;
    if (lx_straddulong(&data, body.len, 10)) die_nomem();
    header_setstr(blob_header_send, "Content-Length", data.s, data.len);

    resp_sendprefix(&req, hterridx);
    resp_sendheaders(&req, blob_header_send);

    if (!global_flags.header_only)
        (void) lx_gdstrput(gd_out, &body);

JUSTDIE:
    (void) lx_gdflush(gd_out);

    _exit(1);
}
Esempio n. 25
0
void doit(char *dir)
{
  struct stat st;
  int r;
  int fd;
  const char *x;
  const char *fntemp;
  char status[40];

  buffer_puts(&b,dir);
  buffer_puts(&b,": ");

  if (chdir(dir) == -1) {
    x = error_str(errno);
    buffer_puts(&b,"unable to chdir: ");
    buffer_puts(&b,x);
    return;
  }
  if (!svpath_init()) {
    strerr_warn4(WARNING,"unable to set up control path for ",dir,": ",&strerr_sys);
    return;
  }

  normallyup = 0;
  if (stat("down",&st) == -1) {
    if (errno != error_noent) {
      x = error_str(errno);
      buffer_puts(&b,"unable to stat down: ");
      buffer_puts(&b,x);
      return;
    }
    normallyup = 1;
  }

  if ((fntemp = svpath_make("/ok")) == 0) die_nomem();
  fd = open_write(fntemp);
  if (fd == -1) {
    if (errno == error_nodevice) {
      buffer_puts(&b,"supervise not running");
      return;
    }
    x = error_str(errno);
    buffer_puts(&b,"unable to open ");
    buffer_puts(&b,fntemp);
    buffer_puts(&b,": ");
    buffer_puts(&b,x);
    return;
  }
  close(fd);

  if ((fntemp = svpath_make("/status")) == 0) die_nomem();
  fd = open_read(fntemp);
  if (fd == -1) {
    x = error_str(errno);
    buffer_puts(&b,"unable to open ");
    buffer_puts(&b,fntemp);
    buffer_puts(&b,": ");
    buffer_puts(&b,x);
    return;
  }
  r = buffer_unixread(fd,status,sizeof status);
  close(fd);
  if (r < 18) {
    if (r == -1)
      x = error_str(errno);
    else
      x = "bad format";
    buffer_puts(&b,"unable to read ");
    buffer_puts(&b,fntemp);
    buffer_puts(&b,": ");
    buffer_puts(&b,x);
    return;
  }
  showstatus(status,r);
  if (r >= 20+18) {
    buffer_puts(&b,"\n");
    buffer_puts(&b,dir);
    buffer_puts(&b," log: ");
    showstatus(status+20,r-20);
  }
}
Esempio n. 26
0
void main(int argc,char **argv)
{
  DIR *bouncedir, *bsdir, *hdir;
  direntry *d, *ds;
  unsigned long bouncedate;
  unsigned long bouncetimeout = BOUNCE_TIMEOUT;
  unsigned long lockout = 0L;
  unsigned long ld;
  unsigned long ddir,dfile;
  int fdlock,fd;
  int opt;
  char ch;

  (void) umask(022);
  sig_pipeignore();
  when = (unsigned long) now();
  while ((opt = getopt(argc,argv,"dDl:t:vV")) != opteof)
    switch(opt) {
      case 'd': flagdig = 1; break;
      case 'D': flagdig = 0; break;
      case 'l':
                if (optarg) {	/* lockout in seconds */
                  (void) scan_ulong(optarg,&lockout);
                }
                break;
      case 't':
                if (optarg) {	/* bouncetimeout in days */
                  (void) scan_ulong(optarg,&bouncetimeout);
                  bouncetimeout *= 3600L * 24L;
                }
                break;
      case 'v':
      case 'V': strerr_die2x(0, "ezmlm-warn version: ",auto_version);
      default:
	die_usage();
    }
  startup(dir = argv[optind]);
  load_config(dir);
  getconf_ulong(&copylines,"copylines",0,dir);
  if (flagdig) {
    if (!stralloc_copys(&digdir,dir)) die_nomem();
    if (!stralloc_cats(&digdir,"/digest")) die_nomem();
    if (!stralloc_0(&digdir)) die_nomem();
    workdir = digdir.s;
  } else
    workdir = dir;

  if (!stralloc_copys(&fnlastd,workdir)) die_nomem();
  if (!stralloc_cats(&fnlastd,"/bounce/lastd")) die_nomem();
  if (!stralloc_0(&fnlastd)) die_nomem();
  if (slurp(fnlastd.s,&lastd,16) == -1)		/* last time d was scanned */
      strerr_die4sys(111,FATAL,ERR_READ,fnlastd.s,": ");
  if (!stralloc_0(&lastd)) die_nomem();
  (void) scan_ulong(lastd.s,&ld);
  if (!lockout)
    lockout = bouncetimeout / 50;		/* 5.6 h for default timeout */
  if (ld + lockout > when && ld < when)
    _exit(0);		/* exit silently. Second check is to prevent lockup */
			/* if lastd gets corrupted */

  if (!stralloc_copy(&fnlasth,&fnlastd)) die_nomem();
  fnlasth.s[fnlasth.len - 2] = 'h';		/* bad, but feels good ... */

  if (flagdig)
    if (!stralloc_cats(&outlocal,"-digest")) die_nomem();

  ddir = when / 10000;
  dfile = when - 10000 * ddir;

  if (!stralloc_copys(&line,workdir)) die_nomem();
  if (!stralloc_cats(&line,"/lockbounce")) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  fdlock = lockfile(line.s);

  if (!stralloc_copys(&line,workdir)) die_nomem();
  if (!stralloc_cats(&line,"/bounce/d")) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  bouncedir = opendir(line.s);
  if (!bouncedir) {
    if (errno != error_noent)
      strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
    else
      _exit(0);		/* no bouncedir - no bounces! */
  }

  while ((d = readdir(bouncedir))) {		/* dxxx/ */
    if (str_equal(d->d_name,".")) continue;
    if (str_equal(d->d_name,"..")) continue;

    scan_ulong(d->d_name,&bouncedate);
	/* since we do entire dir, we do files that are not old enough. */
	/* to not do this and accept a delay of 10000s (2.8h) of the oldest */
	/* bounce we add to bouncedate. We don't if bouncetimeout=0 so that */
	/* that setting still processes _all_ bounces. */
    if (bouncetimeout) ++bouncedate;
    if (when >= bouncedate * 10000 + bouncetimeout) {
      if (!stralloc_copys(&bdname,workdir)) die_nomem();
      if (!stralloc_cats(&bdname,"/bounce/d/")) die_nomem();
      if (!stralloc_cats(&bdname,d->d_name)) die_nomem();
      if (!stralloc_0(&bdname)) die_nomem();
      bsdir = opendir(bdname.s);
      if (!bsdir) {
	if (errno != error_notdir)
	  strerr_die4sys(111,FATAL,ERR_OPEN,bdname.s,":y ");
	else {				/* leftover nnnnn_dmmmmm file */
	  if (unlink(bdname.s) == -1)
	    strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": ");
	  continue;
	}
      }
      while ((ds = readdir(bsdir))) {			/* dxxxx/yyyy */
	if (str_equal(ds->d_name,".")) continue;
	if (str_equal(ds->d_name,"..")) continue;
	if (!stralloc_copy(&fn,&bdname)) die_nomem();	/* '\0' at end */
	  fn.s[fn.len - 1] = '/';
	if (!stralloc_cats(&fn,ds->d_name)) die_nomem();
	if (!stralloc_0(&fn)) die_nomem();
	if ((ds->d_name[0] == 'd') || (ds->d_name[0] == 'w'))
	  doit(ds->d_name[0] == 'w');
        else				/* other stuff is junk */
	  if (unlink(fn.s) == -1)
	    strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
      }
      closedir(bsdir);
      if (rmdir(bdname.s) == -1)	/* the directory itself */
      if (errno != error_noent)
	   strerr_die4sys(111,FATAL,ERR_DELETE,bdname.s,": ");
    }
  }
  closedir(bouncedir);

  if (!stralloc_copy(&line,&fnlastd)) die_nomem();
  line.s[line.len - 2] = 'D';
  fd = open_trunc(line.s);			/* write lastd. Do safe */
						/* since we read before lock*/
  if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
  if (substdio_put(&ssout,strnum,fmt_ulong(strnum,when)) == -1)
    strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": ");
  if (substdio_put(&ssout,"\n",1) == -1)	/* prettier */
    strerr_die4sys(111,FATAL,ERR_WRITE,line.s,": ");
  if (substdio_flush(&ssout) == -1)
    strerr_die4sys(111,FATAL,ERR_FLUSH,line.s,": ");
  if (fsync(fd) == -1)
    strerr_die4sys(111,FATAL,ERR_SYNC,line.s,": ");
  if (close(fd) == -1)
    strerr_die4sys(111,FATAL,ERR_CLOSE,line.s,": ");

  if (rename(line.s,fnlastd.s) == -1)
    strerr_die4sys(111,FATAL,ERR_MOVE,fnlastd.s,": ");

				/* no need to do h dir cleaning more than */
				/* once per 1-2 days (17-30 days for all) */
  if (stat(fnlasth.s,&st) == -1) {
    if (errno != error_noent)
      strerr_die4sys(111,FATAL,ERR_STAT,fnlasth.s,": ");
  } else if (when < (unsigned long)st.st_mtime + 100000
	     && when > (unsigned long)st.st_mtime)
    _exit(0);			/* 2nd comp to guard against corruption */

  if (slurp(fnlasth.s,&lasth,16) == -1)		/* last h cleaned */
      strerr_die4sys(111,FATAL,ERR_READ,fnlasth.s,": ");
  if (!stralloc_0(&lasth)) die_nomem();
  ch = lasth.s[0];				 /* clean h */
  if (ch >= 'a' && ch <= 'o')
    ++ch;
  else
    ch = 'a';
  lasth.s[0] = ch;
  if (!stralloc_copys(&line,workdir)) die_nomem();
  if (!stralloc_cats(&line,"/bounce/h/")) die_nomem();
  if (!stralloc_catb(&line,lasth.s,1)) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  hdir = opendir(line.s);		/* clean ./h/xxxxxx */

  if (!hdir) {
    if (errno != error_noent)
    strerr_die4sys(111,FATAL,ERR_OPEN,line.s,": ");
  } else {

    while ((d = readdir(hdir))) {
      if (str_equal(d->d_name,".")) continue;
      if (str_equal(d->d_name,"..")) continue;
      if (!stralloc_copys(&fn,line.s)) die_nomem();
      if (!stralloc_append(&fn,"/")) die_nomem();
      if (!stralloc_cats(&fn,d->d_name)) die_nomem();
      if (!stralloc_0(&fn)) die_nomem();
      if (stat(fn.s,&st) == -1) {
	if (errno == error_noent) continue;
	strerr_die4sys(111,FATAL,ERR_STAT,fn.s,": ");
      }
      if (when > st.st_mtime + 3 * bouncetimeout)
	if (unlink(fn.s) == -1)
          strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
    }
    closedir(hdir);
  }

  fd = open_trunc(fnlasth.s);			/* write lasth */
  if (fd == -1) strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  substdio_fdbuf(&ssout,write,fd,outbuf,sizeof(outbuf));
  if (substdio_put(&ssout,lasth.s,1) == -1)
    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  if (substdio_put(&ssout,"\n",1) == -1)	/* prettier */
    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  if (substdio_flush(&ssout) == -1)
    strerr_die4sys(111,FATAL,ERR_OPEN,fnlasth.s,": ");
  (void) close(fd);		/* no big loss. No reason to flush/sync */
				/* See check of ld above to guard against */
				/* it being corrupted and > when */

  closesub();
  _exit(0);
}
Esempio n. 27
0
const char *issub(const char *dir,
		  const char *subdir,
		  const char *userhost)
/* Returns (char *) to match if userhost is in the subscriber database      */
/* dir, 0 otherwise. dir is a base directory for a list and may NOT         */
/* be NULL        */
/* NOTE: The returned pointer is NOT VALID after a subsequent call to issub!*/

{
  MYSQL_RES *result;
  MYSQL_ROW row;
  const char *ret;
  const char *table;
  unsigned long *lengths;

  unsigned int j;

  if ((ret = opensub(dir,subdir,&table))) {
    if (*ret) strerr_die2x(111,FATAL,ret);

    return std_issub(dir,subdir,userhost);

  } else {						/* SQL version  */
	/* SELECT address FROM list WHERE address = 'userhost' AND hash */
	/* BETWEEN 0 AND 52. Without the hash restriction, we'd make it */
	/* even easier to defeat. Just faking sender to the list name would*/
	/* work. Since sender checks for posts are bogus anyway, I don't */
	/* know if it's worth the cost of the "WHERE ...". */

    if (!stralloc_copys(&addr,userhost)) die_nomem();
    j = byte_rchr(addr.s,addr.len,'@');
    if (j == addr.len) return 0;
    case_lowerb(addr.s + j + 1,addr.len - j - 1);

    if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem();
    if (!stralloc_cats(&line,table)) die_nomem();
    if (!stralloc_cats(&line," WHERE address = '")) die_nomem();
    if (!stralloc_ready(&quoted,2 * addr.len + 1)) die_nomem();
    if (!stralloc_catb(&line,quoted.s,
	mysql_escape_string(quoted.s,userhost,addr.len))) die_nomem();
    if (!stralloc_cats(&line,"'"))
		die_nomem();
    if (mysql_real_query(mysql,line.s,line.len))	/* query */
		strerr_die2x(111,FATAL,mysql_error(mysql));
    if (!(result = mysql_use_result(mysql)))
		strerr_die2x(111,FATAL,mysql_error(mysql));
    row = mysql_fetch_row(result);
    ret = (char *) 0;
    if (!row) {		/* we need to return the actual address as other */
			/* dbs may accept user-*@host, but we still want */
			/* to make sure to send to e.g the correct moderator*/
			/* address. */
      if (!mysql_eof(result))
		strerr_die2x(111,FATAL,mysql_error(mysql));
    } else {
      if (!(lengths = mysql_fetch_lengths(result)))
		strerr_die2x(111,FATAL,mysql_error(mysql));
      if (!stralloc_copyb(&line,row[0],lengths[0])) die_nomem();
      if (!stralloc_0(&line)) die_nomem();
      ret = line.s;
      while ((row = mysql_fetch_row(result)));	/* maybe not necessary */
      mysql_free_result(result);
    }
    return ret;
  }
}
Esempio n. 28
0
void doit(int flagw)
{
  unsigned int i;
  int fd;
  int match;
  int fdhash;
  const char *err;

  fd = open_read(fn.s);
  if (fd == -1) die_read();
  substdio_fdbuf(&ssin,read,fd,inbuf,sizeof(inbuf));

  if (getln(&ssin,&addr,&match,'\0') == -1) die_read();
  if (!match) { close(fd); return; }
  if (!issub(workdir,0,addr.s)) { close(fd); /*XXX*/unlink(fn.s); return; }
  cookie(hash,"",0,"",addr.s,"");
  if (!stralloc_copys(&fnhash,workdir)) die_nomem();
  if (!stralloc_cats(&fnhash,"/bounce/h/")) die_nomem();
  if (!stralloc_catb(&fnhash,hash,1)) die_nomem();
  if (!stralloc_cats(&fnhash,"/h")) die_nomem();
  if (!stralloc_catb(&fnhash,hash+1,COOKIE-1)) die_nomem();
  if (!stralloc_0(&fnhash)) die_nomem();

  if (qmail_open(&qq, (stralloc *) 0) == -1)
    strerr_die2sys(111,FATAL,ERR_QMAIL_QUEUE);

  hdr_add2("Mailing-List: ",mailinglist.s,mailinglist.len);
  if (listid.len > 0)
    hdr_add2("\nList-ID: ",listid.s,listid.len);
  hdr_datemsgid(now());
  if (flagcd) {
    if (!stralloc_0(&line)) die_nomem();
  }
  hdr_from("-help");
  if (!quote2(&quoted,addr.s)) die_nomem();
  hdr_add2("To: ",quoted.s,quoted.len);
  /* to accomodate transfer-encoding */
  hdr_mime(flagcd ? CTYPE_MULTIPART : CTYPE_TEXT);
  hdr_listsubject1(flagw ? "probe from " : "warning from ");

  if (flagcd) {			/* first part for QP/base64 multipart msg */
    hdr_boundary(0);
    hdr_ctype(CTYPE_TEXT);
    hdr_transferenc();
  } else
    qmail_puts(&qq,"\n");

  copy(&qq,"text/top",flagcd);
  copy(&qq,flagw ? "text/bounce-probe" : "text/bounce-warn",flagcd);

  if (!flagw) {
    if (flagdig)
      copy(&qq,"text/dig-bounce-num",flagcd);
    else
      copy(&qq,"text/bounce-num",flagcd);
    if (!flagcd) {
      fdhash = open_read(fnhash.s);
      if (fdhash == -1) {
        if (errno != error_noent)
          strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": ");
      } else {
        substdio_fdbuf(&sstext,read,fdhash,textbuf,sizeof(textbuf));
        for(;;) {
          if (getln(&sstext,&line,&match,'\n') == -1)
            strerr_die4sys(111,FATAL,ERR_READ,fnhash.s,": ");
          if (!match) break;
          code_qput(line.s,line.len);
        }
      }
      close(fdhash);
    } else {
      if (!stralloc_copys(&line,"")) die_nomem();	/* slurp adds! */
      if (slurp(fnhash.s,&line,256) < 0)
        strerr_die4sys(111,FATAL,ERR_OPEN,fnhash.s,": ");
      code_qput(line.s,line.len);
    }
  }

  copy(&qq,"text/bounce-bottom",flagcd);
  if (flagcd) {
    if (flagcd == 'B') {
      encodeB("",0,&line,2);
      qmail_put(&qq,line.s,line.len);	/* flush */
    }
    hdr_boundary(0);
    hdr_ctype(CTYPE_MESSAGE);
    qmail_puts(&qq,"\n");
  }
  if (qmail_copy(&qq,&ssin,copylines) < 0) die_read();
  close(fd);

  if (flagcd)				/* end multipart/mixed */
    hdr_boundary(1);

  strnum[fmt_ulong(strnum,when)] = 0;
  cookie(hash,key.s,key.len,strnum,addr.s,flagw ? "P" : "W");
  if (!stralloc_copy(&line,&outlocal)) die_nomem();
  if (!stralloc_cats(&line,flagw ? "-return-probe-" : "-return-warn-"))
	die_nomem();
  if (!stralloc_cats(&line,strnum)) die_nomem();
  if (!stralloc_cats(&line,".")) die_nomem();
  if (!stralloc_catb(&line,hash,COOKIE)) die_nomem();
  if (!stralloc_cats(&line,"-")) die_nomem();
  i = str_chr(addr.s,'@');
  if (!stralloc_catb(&line,addr.s,i)) die_nomem();
  if (addr.s[i]) {
    if (!stralloc_cats(&line,"=")) die_nomem();
    if (!stralloc_cats(&line,addr.s + i + 1)) die_nomem();
  }
  if (!stralloc_cats(&line,"@")) die_nomem();
  if (!stralloc_cat(&line,&outhost)) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  qmail_from(&qq,line.s);

  qmail_to(&qq,addr.s);
  if (*(err = qmail_close(&qq)) != '\0')
    strerr_die3x(111,FATAL,ERR_TMP_QMAIL_QUEUE, err + 1);

  strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
  strerr_warn2("ezmlm-warn: info: qp ",strnum,0);

  if (!flagw) {
    if (unlink(fnhash.s) == -1)
      if (errno != error_noent)
        strerr_die4sys(111,FATAL,ERR_DELETE,fnhash.s,": ");
  }
  if (unlink(fn.s) == -1)
    strerr_die4sys(111,FATAL,ERR_DELETE,fn.s,": ");
}
Esempio n. 29
0
int main(int argc,char **argv)
{
  int child;
  const char *sendargs[4];
  stralloc addr = {0};
  unsigned int pos = 0,pos2,poslocal,len;
  const char *cp;

  unsigned long hh = 4L;		/* default time 04:12 */
  unsigned long mm = 12L;
  const char *dow = "*";		/* day of week */
  const char *qmail_inject = "/bin/qmail-inject ";
  char strnum[FMT_ULONG];
  unsigned long uid,euid = 0;

  stralloc rp = {0};
  stralloc user = {0};
  stralloc euser = {0};
  stralloc dir = {0};
  stralloc listaddr = {0};
  stralloc line = {0};

  struct passwd *ppasswd;

  int match;
  int hostmatch;
  int localmatch;
  unsigned long dh,t;
  int founduser = 0;
  int listmatch = 0;
  int flagdigit = 0;
  int flagours;
  int foundlocal = 0;
  int foundmatch = 0;
  unsigned int nolists = 0;
  unsigned long maxlists;
  unsigned int lenhost,lenlocal;
  int fdin,fdout = -1;

  char *local = (char *) 0;	/* list = local@host */
  const char *host = (char *) 0;
  char *code = (char *) 0;	/* digest code */

  char inbuf[512];
  substdio ssin;

  char outbuf[512];
  substdio ssout;

  (void) umask(077);
  sig_pipeignore();

  optind = getconfopt(argc,argv,options,0,0);
  if (flagt != 0) {
    pos = scan_ulong(flagt,&hh);
    if (flagt[pos++] != ':') die_usage();
    (void) scan_ulong(flagt + pos,&mm);
  }
  if (flagw != 0) {
    dow = flagw;
    cp = flagw - 1;
    while (*(++cp)) {
      if (*cp >= '0' && *cp <= '7') {
	if (flagdigit) die_dow();
	flagdigit = 1;
      } else if (*cp == ',') {
	if (!flagdigit) die_dow();
	flagdigit = 0;
      } else
	die_dow();
    }
  }

  if (flaglist + flagdelete + flagconfig > 1)
    strerr_die2x(100,FATAL,MSG(ERR_EXCLUSIVE));
  uid = getuid();
  if (uid && !(euid = geteuid()))
    strerr_die2x(100,FATAL,MSG(ERR_SUID));
  if (!(ppasswd = getpwuid(uid)))
    strerr_die2x(100,FATAL,MSG(ERR_UID));
  if (!stralloc_copys(&user,ppasswd->pw_name)) die_nomem();
  if (!stralloc_0(&user)) die_nomem();
  if (!(ppasswd = getpwuid(euid)))
    strerr_die2x(100,FATAL,MSG(ERR_EUID));
  if (!stralloc_copys(&dir,ppasswd->pw_dir)) die_nomem();
  if (!stralloc_0(&dir)) die_nomem();
  if (!stralloc_copys(&euser,ppasswd->pw_name)) die_nomem();
  if (!stralloc_0(&euser)) die_nomem();

  wrap_chdir(dir.s);

  local = argv[optind++];	/* list address, optional for -c & -l */
  if (!local) {
    if (!flagconfig && !flaglist)
      die_usage();
    lenlocal = 0;
    lenhost = 0;
  } else {
    if (!stralloc_copys(&listaddr,local)) die_nomem();
    if (!isclean(local,1))
      die_argument();
    pos = str_chr(local,'@');
    lenlocal = pos;
    local[pos] = '\0';
    host = local + pos + 1;
    lenhost = str_len(host);
    code = argv[optind];
    if (!code) {		/* ignored for -l, -c, and -d */
      if (flagdelete || flaglist || flagconfig)
				/* get away with not putting code for delete */
        code = (char*)"a";	/* a hack - so what! */
      else
        die_usage();
    } else
      if (!isclean(code,0))
        die_argument();
  }
  if ((fdin = open_read(TXT_EZCRONRC)) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_OPEN,TXT_EZCRONRC));
	/* first line is special */
  substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
  if (getln(&ssin,&line,&match,'\n') == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC));

  if (!match)
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC));
	/* (since we have match line.len has to be >= 1) */
  line.s[line.len - 1] = '\0';
  if (!isclean(line.s,0))	 /* host for bounces */
    strerr_die2x(100,FATAL,MSG1(ERR_CFHOST,TXT_EZCRONRC));
  if (!stralloc_copys(&rp,line.s)) die_nomem();

  match = 1;
  for(;;) {
    if (!match) break;		/* to allow last line without '\n' */
    if (getln(&ssin,&line,&match,'\n') == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,TXT_EZCRONRC));
    if (!line.len)
      break;
    line.s[line.len-1] = '\0';
    if (!case_startb(line.s,line.len,user.s))
      continue;
    pos = user.len - 1;
    if (pos >= line.len || line.s[pos] != ':')
      continue;
    founduser = 1;		 /* got user line */
    break;
  }
  close(fdin);
  if (!founduser)
    strerr_die2x(100,FATAL,MSG(ERR_BADUSER));
  
  if (flagconfig) {
    line.s[line.len-1] = '\n';	/* not very elegant ;-) */
    substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf));
    if (substdio_put(&ssout,line.s,line.len) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
    if (substdio_flush(&ssout) == -1)
      strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
    _exit(0);
  }
  ++pos;				/* points to first ':' */
  len = str_chr(line.s+pos,':');	/* second ':' */
    if (!line.s[pos + len])
      die_syntax(&line);
  if (!local) {				/* only -d and std left */
    localmatch = 1;
    hostmatch = 1;
  } else {
    hostmatch = 0;
    if (len <= str_len(local))
      if (!str_diffn(line.s+pos,local,len))
        localmatch = 1;
  }
  pos += len + 1;
  len = str_chr(line.s + pos,':');	/* third */
  if (!line.s[pos + len])
    die_syntax(&line);
  if (local) {				/* check host */
    if (len == 0)			/* empty host => any host */
      hostmatch = 1;
    else
      if (len == str_len(host))
        if (!case_diffb(line.s+pos,len,host))
          hostmatch = 1;
  }
  pos += len + 1;
  pos += scan_ulong(line.s+pos,&maxlists);
  if (line.s[pos]) {			/* check additional lists */
    if (line.s[pos] != ':')
      die_syntax(&line);
    if (line.s[pos+1+str_chr(line.s+pos+1,':')])
      die_syntax(&line);	/* reminder lists are not separated by ':'  */
				/* otherwise a ':' or arg miscount will die */
				/* silently */
    if (local) {
      while (++pos < line.len) {
        len = str_chr(line.s + pos,'@');
        if (len == lenlocal && !str_diffn(line.s + pos,local,len)) {
          pos += len;
          if (!line.s[pos]) break;
          pos++;
          len = str_chr(line.s+pos,',');
            if (len == lenhost && !case_diffb(line.s+pos,len,host)) {
              listmatch = 1;
              break;
            }
        }
        pos += len;
      }
    }
  }
  if (!listmatch) {
    if (!hostmatch)
      strerr_die2x(100,FATAL,MSG(ERR_BADHOST));
    if (!localmatch)
      strerr_die2x(100,FATAL,MSG(ERR_BADLOCAL));
  }
	/* assemble correct line */
  if (!flaglist) {
    if (!stralloc_copyb(&addr,strnum,fmt_ulong(strnum,mm))) die_nomem();
    if (!stralloc_cats(&addr," ")) die_nomem();
    dh = 0L;
    if (deltah <= 3L) dh = deltah;
    else if (deltah <= 6L) dh = 6L;
    else if (deltah <= 12L) dh = 12L;
    else if (deltah <= 24L) dh = 24L;
    else if (deltah <= 48L) {
      if (dow[0] == '*') dow = "1,3,5";
    } else if (deltah <= 72L) {
      if (dow[0] == '*') dow = "1,4";
    } else
    if (dow[0] == '*') dow = "1";

    if (!dh) {
      if (!stralloc_cats(&addr,"*")) die_nomem();
    } else {
      if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,hh))) die_nomem();
      for (t = hh + dh; t < hh + 24L; t+=dh) {
        if (!stralloc_cats(&addr,",")) die_nomem();
        if (!stralloc_catb(&addr,strnum,fmt_ulong(strnum,t % 24L))) die_nomem();
      }
    }
    if (!stralloc_cats(&addr," * * ")) die_nomem();
    if (!stralloc_cats(&addr,dow)) die_nomem();
    if (!stralloc_cats(&addr," ")) die_nomem();
    if (!stralloc_cats(&addr,auto_qmail)) die_nomem();
    if (!stralloc_cats(&addr,qmail_inject)) die_nomem();
    if (!stralloc_cats(&addr,local)) die_nomem();
    if (!stralloc_cats(&addr,"-dig-")) die_nomem();
    if (!stralloc_cats(&addr,code)) die_nomem();
    if (!stralloc_cats(&addr,"@")) die_nomem();
    if (!stralloc_cats(&addr,host)) die_nomem();
		/* feed 'Return-Path: <user@host>' to qmail-inject */
    if (!stralloc_cats(&addr,"%Return-path: <")) die_nomem();
    if (!stralloc_cats(&addr,user.s)) die_nomem();
    if (!stralloc_cats(&addr,"@")) die_nomem();
    if (!stralloc_cat(&addr,&rp)) die_nomem();
    if (!stralloc_cats(&addr,">\n")) die_nomem();
  }
  if (!stralloc_0(&addr)) die_nomem();

  if (!flaglist) {
	/* now to rewrite crontab we need to lock */
    lockfile("crontabl");
  } /* if !flaglist */
  if ((fdin = open_read("crontab")) == -1) {
    if (errno != error_noent)
      strerr_die2sys(111,FATAL,MSG1(ERR_READ,"crontab"));
  } else
    substdio_fdbuf(&ssin,read,fdin,inbuf,sizeof(inbuf));
  if (flaglist)
    substdio_fdbuf(&ssout,write,1,outbuf,sizeof(outbuf));
  else {
    if ((fdout = open_trunc("crontabn")) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn"));
    substdio_fdbuf(&ssout,write,fdout,outbuf,sizeof(outbuf));
  }
  line.len = 0;

  if (fdin != -1) {
    for (;;) {
      if (!flaglist && line.len) {
        line.s[line.len-1] = '\n';
        if (substdio_put(&ssout,line.s,line.len) == -1)
          strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn"));
      }
      if (getln(&ssin,&line,&match,'\n') == -1)
        strerr_die2sys(111,FATAL,MSG1(ERR_READ,"crontab"));
      if (!match)
        break;
      flagours = 0;			/* assume entry is not ours */
      foundlocal = 0;
      line.s[line.len - 1] = '\0';	/* match so at least 1 char */
      pos = 0;
      while (line.s[pos] == ' ' || line.s[pos] == '\t') ++pos;
      if (line.s[pos] == '#')
        continue;			/* cron comment */
      pos = str_chr(line.s,'/');
      if (!str_start(line.s+pos,auto_qmail)) continue;
      pos += str_len(auto_qmail);
      if (!str_start(line.s+pos,qmail_inject)) continue;
      pos += str_len(qmail_inject);
      poslocal = pos;
      pos = byte_rchr(line.s,line.len,'<');	/* should be Return-Path: < */
      if (pos == line.len)
        continue;			/* not ezmlm-cron line */
      pos++;
     len = str_chr(line.s+pos,'@');
      if (len == user.len - 1 && !str_diffn(line.s+pos,user.s,len)) {
        flagours = 1;
        ++nolists;		/* belongs to this user */
      }
      if (!local) {
        foundlocal = 1;
      } else {
        pos = poslocal + str_chr(line.s+poslocal,'@');
        if (pos + lenhost +1 >= line.len) continue;
        if (case_diffb(line.s+pos+1,lenhost,host)) continue;
        if (line.s[pos+lenhost+1] != '%') continue;
				/* check local */
        if (poslocal + lenlocal + 5 >= line.len) continue;
        if (!str_start(line.s+poslocal,local)) continue;
        pos2 = poslocal+lenlocal;
        if (!str_start(line.s+pos2,"-dig-")) continue;
        foundlocal = 1;
      }
      if (foundlocal) {
        foundmatch = 1;
        if (flaglist && (local || flagours)) {
          if (substdio_put(&ssout,line.s,line.len) == -1)
            strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
          if (substdio_put(&ssout,"\n",1) == -1)
            strerr_die2sys(111,FATAL,MSG(ERR_WRITE_STDOUT));
        }
        line.len = 0;		/* same - kill line */
        if (flagours)
          --nolists;
      }
    }
    close(fdin);
  }
  if (flaglist) {
    if (substdio_flush(&ssout) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,"stdout"));
    if (foundmatch)		/* means we had a match */
      _exit(0);
    else
      strerr_die2x(100,FATAL,MSG(ERR_NO_MATCH));
  }
	/* only -d and regular use left */

  if (nolists >= maxlists && !flagdelete)
    strerr_die2x(100,FATAL,MSG(ERR_LISTNO));
  if (!flagdelete)
    if (substdio_put(&ssout,addr.s,addr.len-1) == -1)
      strerr_die2sys(111,FATAL,MSG1(ERR_WRITE,"crontabn"));
  if (flagdelete && !foundlocal)
    strerr_die2x(111,FATAL,MSG(ERR_NO_MATCH));
  if (substdio_flush(&ssout) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_FLUSH,"crontabn"));
  if (fsync(fdout) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_SYNC,"crontabn++"));
  if (close(fdout) == -1)
    strerr_die2sys(111,FATAL,MSG1(ERR_CLOSE,"crontabn"));
  wrap_rename("crontabn","crontab");
  sendargs[0] = "sh";
  sendargs[1] = "-c";

  if (!stralloc_copys(&line,auto_cron)) die_nomem();
  if (!stralloc_cats(&line,"/crontab '")) die_nomem();
  if (!stralloc_cats(&line,dir.s)) die_nomem();
  if (!stralloc_cats(&line,"/crontab'")) die_nomem();
  if (!stralloc_0(&line)) die_nomem();
  sendargs[2] = line.s;
  sendargs[3] = 0;
  if ((child = wrap_fork()) == 0) {
    if (setreuid(euid,euid) == -1)
      strerr_die2sys(100,FATAL,MSG(ERR_SETUID));
    wrap_execvp(sendargs);
  }
  /* parent */
  switch (wrap_waitpid(child)) {
      case 0:
        _exit(0);
      default:
        strerr_die2x(111,FATAL,MSG(ERR_CRONTAB));
  }
}
Esempio n. 30
0
void doio(void) {
  iopause_fd x[2];
  struct taia deadline;
  struct taia now;
  struct taia timeout;

  if (! stralloc_ready(&encinbuf, bufsizein)) die_nomem();
  encin.buf =encin.start =encin.end =encinbuf.s; encin.size =bufsizein;
  if (! stralloc_ready(&decinbuf, bufsizein)) die_nomem();
  decin.buf =decin.start =decin.end =decinbuf.s; decin.size =bufsizein;
  if (! stralloc_ready(&encoubuf, bufsizeou)) die_nomem();
  encou.buf =encou.start =encou.end =encoubuf.s; encou.size =bufsizeou;
  if (! stralloc_ready(&decoubuf, bufsizeou)) die_nomem();
  decou.buf =decou.start =decou.end =decoubuf.s; decou.size =bufsizeou;

  if (client) {
    rc =matrixSslEncodeClientHello(ssl, &decou, 0);
    if (rc != 0) fatalx("unable to encode client hello");
    if (write(fdstdou, decou.start, decou.end -decou.start)
        != (decou.end -decou.start))
      fatal("unable to send client hello");
    if (verbose > 2) info("sending client hello");
    if (verbose > 2) infou("write bytes: ", decou.end -decou.start);
    bytesou +=decou.end -decou.start;
    decou.start =decou.end =decou.buf;
  }

  taia_now(&now);
  taia_uint(&timeout, handshake_timeout);
  taia_add(&timeout, &now, &timeout);

  for (;;) {
    iopause_fd *xx =x;
    int l =2;

    x[0].fd =encpipe[0];
    x[0].events =IOPAUSE_READ;
    x[0].revents =0;
    x[1].fd =fdstdin;
    x[1].events =IOPAUSE_READ;
    x[1].revents =0;

    if ((x[0].fd == -1) || handshake) { --l; ++xx; }
    if (x[1].fd == -1) --l;
    if (! l) return;

    taia_now(&now);
    if (handshake) {
      if (taia_less(&timeout, &now)) {
        if (verbose) info("ssl handshake timeout, exit.");
        return;
      }
      deadline.sec =timeout.sec;
      deadline.nano =timeout.nano;
      deadline.atto =timeout.atto;
    }
    else {
      taia_uint(&deadline, 30);
      taia_add(&deadline, &now, &deadline);
    }
    iopause(xx, l, &deadline, &now);
    
    if (x[0].revents) encode();
    if (x[1].revents) decode();
  }
}