Esempio n. 1
0
int main (int argc, const char * const *argv, const char * const *envp) {
  int opt;
  int wtmp =0;

  progname =*argv;

  while ((opt =getopt(argc, argv, "wV")) != opteof) {
    switch(opt) {
    case 'w':
      wtmp =1;
      break;
    case 'V':
      strerr_warn1("$Id: cb399098f794012a7f5e6a3a7090b2d53b86c08c $", 0);
    case '?':
      usage();
    }
  }
  argv +=optind;

  if (! argv || ! *argv) usage();
  if (utmp_logout(*argv) == -1)
    strerr_die4x(111, WARNING, "unable to logout line ", *argv,
                 " in utmp: no such entry");
  if (wtmp)
    if (wtmp_logout(*argv) == -1)
      strerr_die4sys(111, WARNING,
                     "unable to logout line ", *argv, " in wtmp: ");
  _exit(0);
}
Esempio n. 2
0
int read_old_config(void)
{
  unsigned char ch;
  int fdin;
  int match;

  /* for edit, try to get args from dir/config */
  dirplusmake("/config");
  if ((fdin = open_read(dirplus.s)) == -1) {
    if (errno != error_noent) die_read();
    return 0;
  } else {
    substdio_fdbuf(&sstext,read,fdin,textbuf,sizeof(textbuf));
    for (;;) {
      if (getln(&sstext,&line,&match,'\n') == -1) die_read();
      if (!match) break;
      if (line.s[0] == '#') continue;
      if (line.len == 1) break;
      if (line.s[1] != ':') break;
      line.s[line.len - 1] = '\0';
      switch (ch = line.s[0]) {
      case 'X':
	if (euid > 0 && !flags['c' - 'a'] && (cfname.len == 0))
	  stralloc_copys(&cfname,line.s+2);
	break;	/* for safety: ignore if root */
      case 'T': stralloc_copys(&dot,line.s+2); break;
      case 'L': stralloc_copys(&local,line.s+2); break;
      case 'H': stralloc_copys(&host,line.s+2); break;
      case 'C': stralloc_copys(&code,line.s+2); break;
      case 'F': stralloc_copys(&oldflags,line.s+2); break;
      case 'D': break;	/* no reason to check */
      default:
	if (ch == '0' || (ch >= '3' && ch <= '9')) {
	  if (usecfg && popt[ch - '0'].len == 0)
	    stralloc_copys(&popt[ch-'0'],line.s+2);
	} else
	  strerr_die4x(111,FATAL,MSG1(ERR_SYNTAX,dirplus.s),": ",line.s+2);
	break;
      }
    }
    close(fdin);
  }
  return 1;
}
Esempio n. 3
0
void load_config(const char *dir)
{
  load_flags(dir);

  switch(slurp("key",&key,512)) {
    case -1:
      strerr_die4sys(111,FATAL,ERR_READ,dir,"/key: ");
    case 0:
      strerr_die4x(100,FATAL,dir,"/key",ERR_NOEXIST);
  }

  /* There are problems with using getconf_line to fetch the ezmlmrc
   * pointer, since the alt location for "ezmlmrc" turns out to be the
   * whole ezmlmrc file itself. */
  switch (slurp("ezmlmrc",&ezmlmrc,64)) {
  case -1:
    strerr_die4sys(111,FATAL,ERR_READ,dir,"/ezmlmrc: ");
  case 0:
    ezmlmrc.len = 0;
  }
  ezmlmrc.len = byte_chr(ezmlmrc.s,ezmlmrc.len,'\n');

  getconf_line(&outhost,"outhost",1,dir);
  getconf_line(&outlocal,"outlocal",1,dir);
  if (!stralloc_copy(&local,&outlocal)) die_nomem();

  getconf_line(&listid,"listid",0,dir);
  if (getconf_line(&charset,"charset",0,dir)) {
    if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
      if (charset.s[charset.len - 1] == 'B' ||
		 charset.s[charset.len - 1] == 'Q') {
        flagcd = charset.s[charset.len - 1];
        charset.s[charset.len - 2] = '\0';
      }
    }
  } else
    if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
  if (!stralloc_0(&charset)) die_nomem();

  // FIXME: need to handle escapes in mailinglist
  getconf_line(&mailinglist,"mailinglist",1,dir);
}
Esempio n. 4
0
static void load_config(void)
{
  load_flags();

  key.len = 0;
  switch(slurp("key",&key,512)) {
    case -1:
      strerr_die2sys(111,FATAL,MSG1(ERR_READ,"key"));
    case 0:
      strerr_die4x(100,FATAL,listdir,"/key",MSG(ERR_NOEXIST));
  }

  /* There are problems with using getconf_line to fetch the ezmlmrc
   * pointer, since the alt location for "ezmlmrc" turns out to be the
   * whole ezmlmrc file itself. */
  switch (slurp("ezmlmrc",&ezmlmrc,64)) {
  case -1:
    strerr_die2sys(111,FATAL,MSG1(ERR_READ,"ezmlmrc"));
  case 0:
    ezmlmrc.len = 0;
  }
  ezmlmrc.len = byte_chr(ezmlmrc.s,ezmlmrc.len,'\n');

  getconf_line(&outhost,"outhost",1);
  getconf_line(&outlocal,"outlocal",1);
  if (!stralloc_copy(&local,&outlocal)) die_nomem();

  getconf_line(&listid,"listid",0);
  if (getconf_line(&charset,"charset",0)) {
    if (charset.len >= 2 && charset.s[charset.len - 2] == ':') {
      if (charset.s[charset.len - 1] == 'B' ||
		 charset.s[charset.len - 1] == 'Q') {
        flagcd = charset.s[charset.len - 1];
        charset.s[charset.len - 2] = '\0';
      }
    }
  } else
    if (!stralloc_copys(&charset,TXT_DEF_CHARSET)) die_nomem();
  if (!stralloc_0(&charset)) die_nomem();
}
Esempio n. 5
0
static void forward(const char *rcpt)
{
  char buf[4096];
  const char *dtline;
  const char *err;
  int r;
  if (qmail_open(&qq,0) == -1)
    strerr_die2sys(111,FATAL,MSG(ERR_QMAIL_QUEUE));
  if ((dtline = env_get("DTLINE")) != 0)
    qmail_puts(&qq,dtline);
  while ((r = read(0,buf,sizeof buf)) > 0)
    qmail_put(&qq,buf,r);
  if (r == -1)
    strerr_die2sys(111,FATAL,MSG(ERR_READ_STDIN));
  qmail_from(&qq,sender);
  qmail_to(&qq,rcpt);
  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;
  substdio_puts(subfderr,"qp ");
  substdio_puts(subfderr,strnum);
  substdio_putsflush(subfderr,"\n");
  ++did_forward;
}
Esempio n. 6
0
void
fail(qldap *q, const char *f, int r)
{
	qldap_free(q);
	strerr_die4x(111, FATAL, f ,": ", qldap_err_str(r));
}
Esempio n. 7
0
void usage ()
{
    strerr_die4x(1, "usage: ", progname, USAGE, "\n");
}
Esempio n. 8
0
void makedir(const char *s)
{
  if (mkdir(s,0755) == -1)
    if (errno != error_exist)
      strerr_die4x(111,FATAL,ERR_CREATE,s,": ");
}
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
void fatalx(const char *m0, const char *m1) {
  strerr_die4x(111, FATAL, m0, ": ", m1);
}
Esempio n. 11
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. 12
0
static void fatalmx(char *m0) { strerr_die4x(111, NAME, id, FATAL, m0); }
Esempio n. 13
0
static void die_nomem() {
  strerr_die4x(111, NAME, id, FATAL, "out of memory.");
}
Esempio n. 14
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. 15
0
void setuidgid_usage() {
  strerr_die4x(100, "usage: ", progname, USAGE_SETUIDGID, "\n");
}
Esempio n. 16
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. 17
0
void envuidgid_usage() {
  strerr_die4x(100, "usage: ", progname, USAGE_ENVUIDGID, "\n");
}
Esempio n. 18
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. 19
0
void usage() { strerr_die4x(100, "usage: ", progname, USAGE_MAIN, "\n"); }
Esempio n. 20
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. 21
0
void envdir_usage() {
  strerr_die4x(100, "usage: ", progname, USAGE_ENVDIR, "\n");
}
Esempio n. 22
0
void usage() {
  if (!lsb) strerr_die4x(100, "usage: ", progname, USAGE, "\n");
  strerr_die4x(2, "usage: ", progname, USAGELSB, "\n");
}
Esempio n. 23
0
void pgrphack_usage() {
  strerr_die4x(100, "usage: ", progname, USAGE_PGRPHACK, "\n");
}
Esempio n. 24
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. 25
0
void setlock_usage() {
  strerr_die4x(100, "usage: ", progname, USAGE_SETLOCK, "\n");
}
Esempio n. 26
0
int main(int argc,char **argv)
{
  char *action;
  const char *err;
  unsigned int i;
  int act = AC_NONE;	/* desired action */
  unsigned int actlen = 0;/* str_len of above */

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

  getconfopt(argc,argv,options,1,&dir);
  initsub(0);

  sender = get_sender();
  if (!sender) die_sender();
  action = env_get("DEFAULT");
  if (!action) 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));

  action = set_workdir(action);

  stralloc_copys(&target,sender);
  if (action[0]) {
    i = str_chr(action,'-');
    if (action[i]) {
      action[i] = 0;
      stralloc_copys(&target,action + i + 1);
      i = byte_rchr(target.s,target.len,'=');
      if (i < target.len)
	target.s[i] = '@';
    }
  }
  stralloc_0(&target);
  set_cptarget(target.s);	/* for copy() */
  make_verptarget();

  act = get_act_ismod(action,&actlen);

  stralloc_copy(&from,&outlocal);
  stralloc_cats(&from,"-return-@");
  stralloc_cat(&from,&outhost);
  stralloc_0(&from);

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

  if (act == AC_SUBSCRIBE)
    do_subscribe(action);
  else if (act == AC_SC)
    do_sc(action);
  else if (str_start(action,ACTION_RC))
    do_rc_tc(action,ACTION_RC);
  else if(str_start(action,ACTION_TC))
    do_rc_tc(action,ACTION_TC);
  else if (act == AC_UNSUBSCRIBE)
    do_unsubscribe(action);
  else if (str_start(action,ACTION_UC))
    do_uc(action);
  else if (str_start(action,ACTION_VC))
    do_vc_wc(action,ACTION_VC);
  else if (str_start(action,ACTION_WC))
    do_vc_wc(action,ACTION_WC);
  else if (act == AC_LIST || act == AC_LISTN) 
    do_list(act);
  else if (act == AC_LOG)
    do_log(action,actlen);
  else if (act == AC_EDIT)
    do_edit(action);
  else if (str_start(action,ACTION_ED))
    do_ed(action);
  else if (act == AC_GET)
    do_get(action);
  else if (case_starts(action,ACTION_QUERY) ||
		case_starts(action,ALT_QUERY))
    do_query();
  else if (case_starts(action,ACTION_INFO) ||
		case_starts(action,ALT_INFO))
    do_info();
  else if (case_starts(action,ACTION_FAQ) ||
		case_starts(action,ALT_FAQ))
    do_faq();
  else if (ismod && (act == AC_HELP))
    do_mod_help();
  else
    do_help();

  err = qmail_close(&qq);
  closesub();
  if (*err != '\0')
    strerr_die4x(111,FATAL,MSG(ERR_TMP_QMAIL_QUEUE),": ",err + 1);
  strnum[fmt_ulong(strnum,qmail_qp(&qq))] = 0;
  strerr_die3x(0,INFO,"qp ",strnum);
}
Esempio n. 27
0
void softlimit_usage() {
  strerr_die4x(100, "usage: ", progname, USAGE_SOFTLIMIT, "\n");
}
Esempio n. 28
0
void syntaxerror(const char *why)
{
  strnum[fmt_ulong(strnum,linenum)] = 0;
  strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why);
}
Esempio n. 29
0
int main(int argc, char **argv)
{
	enum { unset, uid, mail, filter } mode = unset;
	qldap	*q, *qpw;
	struct passwd *pw;
	char	*passwd = 0, *value = 0;
	char	*bindpw = 0, *binddn = 0;
	char	*f, *s;
	int	opt, r, done, status, id;
	unsigned int j, slen;
	unsigned long size, count, maxsize;
	
	const char *attrs[] = { LDAP_MAIL,
				LDAP_MAILALTERNATE,
				LDAP_UID,
				LDAP_QMAILUID,
				LDAP_QMAILGID,
				LDAP_ISACTIVE,
				LDAP_MAILHOST,
				LDAP_MAILSTORE,
				LDAP_HOMEDIR,
				LDAP_QUOTA_SIZE,
				LDAP_QUOTA_COUNT,
				LDAP_FORWARDS,
				LDAP_PROGRAM,
				LDAP_MODE,
				LDAP_REPLYTEXT,
				LDAP_DOTMODE,
				LDAP_MAXMSIZE,
				LDAP_OBJECTCLASS,
#if 0
				LDAP_GROUPCONFIRM,
				LDAP_GROUPMEMONLY,
				LDAP_GROUPCONFRIMTEXT,
				LDAP_GROUPMODERATTEXT,
				LDAP_GROUPMODERATDN,
				LDAP_GROUPMODERAT822,
				LDAP_GROUPMEMBERDN,
				LDAP_GROUPMEMBER822,
				LDAP_GROUPMEMBERFILTER,
#endif
				LDAP_PASSWD,
				0};

	while ((opt = getopt(argc, argv, "d:D:u:m:p:f:w:")) != opteof)
		switch (opt) {
		case 'd':
			if (env_put2("LOGLEVEL", optarg) == 0)
				strerr_die2sys(1, FATAL, "setting loglevel: ");
			break;
		case 'D':
			binddn = optarg;
			break;
		case 'u':
			if (value != 0)
				usage();
			value = optarg;
			mode = uid;
			break;
		case 'm':
			if (value != 0)
				usage();
			value = optarg;
			mode = mail;
			break;
		case 'f':
			if (value != 0)
				usage();
			value = optarg;
			mode = filter;
			break;
		case 'p':
			if (geteuid() != 0)
				strerr_die2x(1, FATAL,
				    "only the superuser may comapre passwords");
			passwd = optarg;
			break;
		case 'w':
			bindpw = optarg;
			break;
		default:
			usage();
		}
	if (argc != optind) usage();
	if (bindpw && !binddn) usage();
	
	log_init(STDERR, -1, 0);

	if (read_controls(ctrls) != 0)
		strerr_die2sys(111, FATAL, "unable to read controls: ");
	
	q = qldap_new();
	if (q == 0)
		strerr_die2sys(111, FATAL, "qldap_new failed: ");
	qpw = qldap_new();
	if (qpw == 0)
		strerr_die2sys(111, FATAL, "qldap_new failed: ");
	
	r = qldap_open(q);
	if (r != OK) fail(q, "qldap_open", r);
	r = qldap_open(qpw);
	if (r != OK) fail(qpw, "qldap_open", r);
	r = qldap_bind(q, binddn, bindpw);
	if (r != OK) fail(q, "qldap_bind", r);

	if (passwd == 0 || mode != uid || qldap_need_rebind() != 0)
		attrs[sizeof(attrs)/4 - 2] = 0; /* password */
	done = 0;
	f = 0;
	do {
		switch (mode) {
		case mail:
			f = filter_mail(value, &done);
			if (value == 0)
				strerr_die2sys(1, FATAL, "building filter: ");
			break;
		case uid:
			f = filter_uid(value);
			done = 1;
			if (value == 0)
				strerr_die2sys(1, FATAL, "building filter: ");
			break;
		case filter:
			f = value;
			break;
		default:
			usage();
		}
		output(subfdout, "Searching ldap for: %s\nunder dn: %s\n",
		    f, qldap_basedn());
		r = qldap_filter(q, f, attrs, qldap_basedn(), SCOPE_SUBTREE);
		if (r != OK) fail(q, "qldap_filter", r);

		r = qldap_count(q);
		switch (r) {
		case -1:
			fail(q, "qldap_count", FAILED);
		case 0:
			output(subfdout, "No entries found.\n");
			qldap_free(q);
			/* TODO hook for local lookups. */
			return 0;
		case 1:
			output(subfdout, "Found %i entry:\n", r);
			break;
		default:
			output(subfdout, "Found %i entries:\n", r);
			if (mode == uid || mode == uid) {
				output(subfdout,
				    "Uh-oh: multiple entries found but "
				    "should be unique!\n");
				passwd = 0;
			}
			break;
		}
		output(subfdout, "\n");
	} while (r == 0 && !done);

	r = qldap_first(q);
	if (r != OK) fail(q, "qldap_first", r);;
	do {
		r = qldap_get_dn(q, &dn);
		if (r != OK) fail(q, "qldap_get_dn", r);
		output(subfdout, "dn: %s\n"
		    "-------------------------------------------------------\n",
		    dn.s);
		
		r = qldap_get_attr(q, LDAP_OBJECTCLASS, &foo, MULTI_VALUE);
		if (r != OK) fail(q, "qldap_get_attr(" LDAP_OBJECTCLASS ")", r);
		unescape(foo.s, &bar);
		s = bar.s;
		slen = bar.len-1;
		for(;;) {
			output(subfdout, "%s: %s\n",LDAP_OBJECTCLASS ,s);
			j = byte_chr(s,slen,0);
			if (j++ >= slen) break;
			s += j; slen -= j;
		}
		
		r = qldap_get_attr(q, LDAP_MAIL, &foo, SINGLE_VALUE);
		if (r != OK) fail(q, "qldap_get_attr(" LDAP_MAIL ")", r);
		output(subfdout, "%s: %s\n", LDAP_MAIL, foo.s);

		r = qldap_get_attr(q, LDAP_MAILALTERNATE, &foo, MULTI_VALUE);
		if (r != OK && r != NOSUCH)
			fail(q, "qldap_get_attr(" LDAP_MAILALTERNATE ")", r);
		if (r == OK) {
			unescape(foo.s, &bar);
			s = bar.s;
			slen = bar.len-1;
			for(;;) {
				output(subfdout, "%s: %s\n",
				    LDAP_MAILALTERNATE, s);
				j = byte_chr(s,slen,0);
				if (j++ >= slen) break;
				s += j; slen -= j;
			}
		}
		
		r = qldap_get_user(q, &foo);
		if (r != OK && r != NOSUCH) fail(q, "qldap_get_user", r);
		if (r == OK)
			output(subfdout, "%s: %s\n", LDAP_UID, foo.s);
		else
			output(subfdout, "%s: undefined "
			    "(forward only account required)\n", LDAP_UID);

		r = qldap_get_status(q, &status);
		if (r != OK) fail(q, "qldap_get_status", r);
		switch (status) {
		case STATUS_BOUNCE:
			output(subfdout, "%s: %s\n",
			    LDAP_ISACTIVE, ISACTIVE_BOUNCE);
			break;
		case STATUS_NOACCESS:
			output(subfdout, "%s: %s\n",
			    LDAP_ISACTIVE, ISACTIVE_NOACCESS);
			break;
		case STATUS_OK:
			output(subfdout, "%s: %s\n",
			    LDAP_ISACTIVE, ISACTIVE_ACTIVE);
			break;
		case STATUS_UNDEF:
			output(subfdout, "%s: %s\n", LDAP_ISACTIVE,
			    "undefined -> active");
			break;
		default:
			strerr_warn2(WARN,
			    "qldap_get_status returned unknown status", 0);
		}
		
		r = qldap_get_attr(q, LDAP_MAILHOST, &foo, SINGLE_VALUE);
		if (r != OK && r != NOSUCH)
			fail(q, "qldap_get_attr(" LDAP_MAILHOST ")", r);
		if (r == OK) {
			output(subfdout, "%s: %s\n", LDAP_MAILHOST, foo.s);
			/*
			 * TODO we could check if we are in cluster mode and 
			 * if we would redirect to a differnet host
			 */
		} else
			output(subfdout, "%s: undefined\n", LDAP_MAILHOST);

		/* get the path of the maildir or mbox */
		r = qldap_get_mailstore(q, &foo, &bar);
		switch (r) {
		case OK:
			output(subfdout, "homeDirectory: %s\n", foo.s);
			if (bar.len > 0)
				output(subfdout, "aliasEmpty: %s\n", bar.s);
			else
				output(subfdout, "aliasEmpty: using default\n");
			break;
		case NEEDED:
			output(subfdout,
			    "forward only delivery via alias user\n");
			pw = getpwnam(auto_usera);
			if (!pw)
				strerr_die4x(100, FATAL,
				    "Aiiieeeee, now alias user '",
				    auto_usera, "'found in /etc/passwd.");
			output(subfdout, "alias user: %s\n", pw->pw_name);
			output(subfdout, "alias user uid: %i\n", pw->pw_uid);
			output(subfdout, "alias user gid: %i\n", pw->pw_gid);
			output(subfdout, "alias user home: %s\n", pw->pw_dir);
			output(subfdout, "alias user aliasempty: %s\n",
			    ALIASDEVNULL);
			/* get the forwarding addresses */
			r = qldap_get_attr(q, LDAP_FORWARDS, &foo, MULTI_VALUE);
			if (r != OK)
				fail(q, "qldap_get_attr("
				    LDAP_FORWARDS ") for forward only user", r);
			unescape(foo.s, &bar);
			s = bar.s;
			slen = bar.len-1;
			for(;;) {
				output(subfdout, "%s: %s\n", LDAP_FORWARDS, s);
				j = byte_chr(s,slen,0);
				if (j++ >= slen) break;
				s += j; slen -= j;
			}
			goto next;
		default:
			fail(q, "qldap_get_mailstore", r);
		}
		
		r = qldap_get_dotmode(q, &foo);
		if (r != OK) fail(q, "qldap_get_dotmode", r);
		output(subfdout, "%s: %s\n", LDAP_DOTMODE, foo.s);

		r = qldap_get_uid(q, &id);
		if (r != OK) fail(q, "qldap_get_uid", r);
		output(subfdout, "%s: %i\n", LDAP_QMAILUID, id);
		
		r = qldap_get_gid(q, &id);
		if (r != OK) fail(q, "qldap_get_gid", r);
		output(subfdout, "%s: %i\n", LDAP_QMAILGID, id);
		
		r = qldap_get_quota(q, &size, &count, &maxsize);
		if (r != OK) fail(q, "qldap_get_quota", r);
		output(subfdout, "%s: %u%s\n", LDAP_QUOTA_SIZE, size,
		    size==0?" (unlimited)":"");
		output(subfdout, "%s: %u%s\n", LDAP_QUOTA_COUNT, count,
		    count==0?" (unlimited)":"");
		output(subfdout, "%s: %u%s\n", LDAP_MAXMSIZE, maxsize,
		    maxsize==0?" (unlimited)":"");

		r = qldap_get_attr(q, LDAP_MODE, &foo, MULTI_VALUE);
		if (r != OK && r != NOSUCH)
			fail(q, "qldap_get_attr(" LDAP_MODE ")", r);
		if (r == OK) {
			unescape(foo.s, &bar);
			s = bar.s;
			slen = bar.len-1;
			for(;;) {
				if (case_diffs(MODE_FORWARD, s) &&
				    case_diffs(MODE_REPLY, s) &&
				    case_diffs(MODE_NOLOCAL, s) &&
				    case_diffs(MODE_NOMBOX, s) &&
				    case_diffs(MODE_NOFORWARD, s) &&
				    case_diffs(MODE_NOPROG, s) &&
				    case_diffs(MODE_LOCAL, s) &&
				    case_diffs(MODE_FORWARD, s) &&
				    case_diffs(MODE_PROG, s) &&
				    case_diffs(MODE_NOREPLY, s))
					strerr_warn4(WARN,
					    "undefined mail delivery mode: ",
					    s," (ignored).", 0);
				else if (!case_diffs(MODE_FORWARD, s))
					strerr_warn4(WARN,
					    "mail delivery mode: ",
					    s," should not be used "
					    "(used internally).", 0);
				output(subfdout, "%s: %s\n", LDAP_MODE, s);
				j = byte_chr(s,slen,0);
				if (j++ >= slen) break;
				s += j; slen -= j;
			}
		}

		r = qldap_get_attr(q, LDAP_FORWARDS, &foo, MULTI_VALUE);
		if (r != OK && r != NOSUCH)
			fail(q, "qldap_get_attr(" LDAP_FORWARDS ")", r);
		if (r == OK) {
			unescape(foo.s, &bar);
			s = bar.s;
			slen = bar.len-1;
			for(;;) {
				output(subfdout, "%s: %s\n", LDAP_FORWARDS, s);
				j = byte_chr(s,slen,0);
				if (j++ >= slen) break;
				s += j; slen -= j;
			}
		}

		r = qldap_get_attr(q, LDAP_PROGRAM, &foo, MULTI_VALUE);
		if (r != OK && r != NOSUCH)
			fail(q, "qldap_get_attr(" LDAP_PROGRAM ")", r);
		if (r == OK) {
			unescape(foo.s, &bar);
			s = bar.s;
			slen = bar.len-1;
			for(;;) {
				output(subfdout, "%s: %s\n", LDAP_PROGRAM, s);
				j = byte_chr(s,slen,0);
				if (j++ >= slen) break;
				s += j; slen -= j;
			}
		}

		r = qldap_get_attr(q, LDAP_REPLYTEXT, &foo, SINGLE_VALUE);
		if (r != OK && r != NOSUCH)
			fail(q, "qldap_get_attr(" LDAP_REPLYTEXT ")", r);
		if (r == OK)
			output(subfdout, "%s:\n=== begin ===\n%s\n"
			    "=== end ===\n", LDAP_REPLYTEXT, foo.s);
		else
			output(subfdout, "%s: undefined\n", LDAP_REPLYTEXT);

		if (mode == uid && passwd != 0) {
			if (qldap_need_rebind() == 0) {
				r = qldap_get_attr(q, LDAP_PASSWD,
				    &foo, SINGLE_VALUE);
				if (r != OK) fail(q, "qldap_get_attr("
				    LDAP_PASSWD ")", r);
				r = cmp_passwd(passwd, foo.s);
			} else {
				r = qldap_rebind(qpw, dn.s, passwd);
				switch (r) {
				case OK:
					r = OK;
					break;
				case LDAP_BIND_AUTH:
					r = BADPASS;
					break;
				default:
					break;
				}
			}
			output(subfdout, "\nPASSWORD COMPARE was %s.\n",
			    r == OK?"successful":"NOT successful");
			if (r != OK)
				output(subfdout, "\terror was: %s\n",
				    qldap_err_str(r));
		}

next:
		r = qldap_next(q);
		output(subfdout, "\n\n");
	} while (r == OK);
	if (r != NOSUCH) fail(q, "qldap_next", r);
	qldap_free(q);
	return 0;
}