Example #1
0
void
setup_env(char *user, struct credentials *c)
{
	/* set up the environment for the execution of the subprogram */
	if (!env_put2("USER", user))
		auth_error(ERRNO);
	
	/* only courier-imap needs this but we set it anyway */
	if (!env_put2("AUTHENTICATED", user))
		auth_error(ERRNO);
	
	if (c->home.s != 0 && c->home.len > 0)
		if (!env_put2("HOME", c->home.s))
			auth_error(ERRNO);
	
	if (c->maildir.s != 0 && c->maildir.len > 0) {
		if (!env_put2("MAILDIR", c->maildir.s))
			auth_error(ERRNO);
	} else {
		if (!env_unset("MAILDIR"))
			auth_error(ERRNO);
	}
	logit(32, "environment successfully set: "
	    "USER %s, HOME %s, MAILDIR %s\n",
	    user, c->home.s != 0 && c->home.len > 0?
	    c->home.s:"unset, forwarding",
	    c->maildir.s != 0 && c->maildir.len > 0?
	    c->maildir.s:"unset, using aliasempty"); 
}
Example #2
0
static void execute(const char *fn,const char *def)
     /* Load and execute a qmail command file. */
{
  stralloc file = {0,0,0};
  int code;
  if (def != 0)
    env_put2("DEFAULT",def);
  else
    env_unset("DEFAULT");
  if (slurp(fn,&file,256) != 1)
    strerr_die6sys(111,FATAL,ERR_READ_INPUT,basedir.s,"/",fn,": ");
  code = execute_file(fn,&file);
  substdio_puts(subfderr,"did 0+");
  substdio_put(subfderr,strnum,fmt_ulong(strnum,did_forward));
  substdio_puts(subfderr,"+");
  substdio_put(subfderr,strnum,fmt_ulong(strnum,did_program));
  substdio_putsflush(subfderr,"\n");
  _exit(code);
}
Example #3
0
int
check_ldap(stralloc *login, stralloc *authdata,
    struct credentials *c, int fast)
{
	static	stralloc ld = {0};
	qldap	*q;
	char	*filter;
	int	r, status, pwok, needforward;
	unsigned long count, size, max;
	const	char	*attrs[] = {
				LDAP_UID, /* the first 10 attrs are default */
				LDAP_QMAILUID,
				LDAP_QMAILGID,
				LDAP_ISACTIVE,
				LDAP_MAILHOST,
				LDAP_MAILSTORE,
				LDAP_HOMEDIR,
				LDAP_QUOTA_SIZE,
				LDAP_QUOTA_COUNT,
				LDAP_MAXMSIZE,
				LDAP_PASSWD, 0}; /* passwd is extra */

	/* TODO more debug output is needed */
	needforward = 0;
	q = qldap_new();
	if (q == 0)
		return ERRNO;
	
	r = qldap_open(q);
	if (r != OK) goto fail;
	r = qldap_bind(q, 0, 0);
	if (r != OK) goto fail;
	
	if (fast) {
		/* just comapre passwords and account status */
		attrs[0] = LDAP_ISACTIVE;
		if (qldap_need_rebind() == 0) {
			attrs[1] = LDAP_PASSWD;
			attrs[2] = 0;
		} else
			attrs[1] = 0;
	} else {
		if (qldap_need_rebind() != 0)
			attrs[10] = 0;
	}

	filter = filter_uid(login->s);
	if (filter == 0) { r = ERRNO; goto fail; }

	r = qldap_lookup(q, filter, attrs);
	if (r != OK) goto fail;

	r = qldap_get_status(q, &status);
	if (r != OK) goto fail;
	if (status == STATUS_BOUNCE || status == STATUS_NOACCESS ||
	    status == STATUS_DELETE) {
		qldap_free(q);
		return ACC_DISABLED;
	}
	
	if (!fast) {
#ifdef QLDAP_CLUSTER
		r = qldap_get_attr(q, LDAP_MAILHOST, &c->forwarder,
		    SINGLE_VALUE);
		if (r != OK && r != NOSUCH) goto fail;
		if (r == OK && cluster(c->forwarder.s) == 1) {
			/* hostname is different, so I reconnect */
			logit(8, "check_ldap: forwarding session to %s\n",
			    c->forwarder.s);
			needforward = 1;
		}
#endif

		r = qldap_get_uid(q, &c->uid);
		if (r != OK) goto fail;
		r = qldap_get_gid(q, &c->gid);
		if (r != OK) goto fail;
		r = qldap_get_mailstore(q, &c->home, &c->maildir);
		if (r != OK) goto fail;
		if (!stralloc_0(&c->home) ||
		    !stralloc_0(&c->maildir))
			return ERRNO;
		size = count = max = 0;
		r = qldap_get_quota(q, &size, &count, &max);
		if (r != OK) goto fail;
		if (max != 0) {
			num[fmt_ulong(num, max)] = 0;
			if (!env_put2("DATASIZE", num))
				auth_error(ERRNO);
		}
		if (size != 0 || count != 0) {
			if (!stralloc_copys(&ld, "")) auth_error(ERRNO);
			if (size != 0) {
				if (!stralloc_catb(&ld, num,
					    fmt_ulong(num, size)))
					auth_error(ERRNO);
				if (!stralloc_append(&ld, "S"))
					auth_error(ERRNO);
			}
			if (count != 0) {
				if (size != 0)
					if (!stralloc_append(&ld, ","))
						auth_error(ERRNO);
				if (!stralloc_catb(&ld, num,
					    fmt_ulong(num, count)))
					auth_error(ERRNO);
				if (!stralloc_append(&ld, "C"))
					auth_error(ERRNO);
			}
			if (!stralloc_0(&ld)) auth_error(ERRNO);
			if (!env_put2(ENV_QUOTA, ld.s )) auth_error(ERRNO);
		}
	}
	
	if (qldap_need_rebind() == 0) {
		r = qldap_get_attr(q, LDAP_PASSWD, &ld, SINGLE_VALUE);
		if (r != OK) goto fail;
		pwok = cmp_passwd(authdata->s, ld.s);
	} else {
		r = qldap_get_dn(q, &ld);
		if (r != OK) goto fail;
		r = qldap_rebind(q, ld.s, authdata->s);
		switch (r) {
		case OK:
			pwok = OK;
			break;
		case LDAP_BIND_AUTH:
			pwok = BADPASS;
			break;
		default:
			pwok = r;
			break;
		}
	}
	logit(32, "check_ldap: password compare was %s\n", 
	    pwok == OK?"successful":"not successful");
	qldap_free(q);
	if (pwok == OK  && needforward == 1)
		return FORWARD;
	return pwok;
fail:
	qldap_free(q);
	return r;
	
}
Example #4
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);
   }
}
Example #5
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;
}