Beispiel #1
0
/* return a piece of message starting at `offset' */
extern int
m_get(message *mp, long offset, char **pp)
{
	static char buf[4*1024];

	/*
	 *  are we past eof?
	 */
	if(offset >= mp->size)
		return 0;

	/*
	 *  are we in the virtual memory portion?
	 */
	if(offset < s_len(mp->body)){
		*pp = mp->body->base + offset;
		return mp->body->ptr - mp->body->base - offset;
	}

	/*
	 *  read it from the temp file
	 */
	offset -= s_len(mp->body);
	if(mp->fd < 0)
		return -1;
	if(seek(mp->fd, offset, 0)<0)
		return -1;
	*pp = buf;
	return read(mp->fd, buf, sizeof buf);
}
Beispiel #2
0
/*
 *  print out a header line, expanding any domainless addresses into
 *  address@him
 */
char*
bprintnode(Biobuf *b, Node *p, int *cntp)
{
	int len;

	*cntp = 0;
	if(p->s){
		if(p->addr && strchr(s_to_c(p->s), '@') == nil){
			if(Bprint(b, "%s@%s", s_to_c(p->s), him) < 0)
				return nil;
			*cntp += s_len(p->s) + 1 + strlen(him);
		} else {
			len = s_len(p->s);
			if(Bwrite(b, s_to_c(p->s), len) < 0)
				return nil;
			*cntp += len;
		}
	}else{
		if(Bputc(b, p->c) < 0)
			return nil;
		++*cntp;
	}
	if(p->white) {
		len = s_len(p->white);
		if(Bwrite(b, s_to_c(p->white), len) < 0)
			return nil;
		*cntp += len;
	}
	return p->end+1;
}
Beispiel #3
0
void
main(int argc, char **argv)
{
	int i;
	Biobuf *b;
	String *h;
	Whist *doc;

	ARGBEGIN{
	default:
		usage();
	case 'd':
		wikidir = EARGF(usage());
		break;
	}ARGEND

	if(argc != 1)
		usage();

	if((b = Bopen(argv[0], OREAD)) == nil)
		sysfatal("Bopen: %r");

	if((doc = Brdwhist(b)) == nil)
		sysfatal("Brdwtxt: %r");

	h = nil;
	for(i=0; i<doc->ndoc; i++){
		print("__________________ %d ______________\n", i);
		if((h = pagetext(s_reset(h), doc->doc[i].wtxt, 1)) == nil)
			sysfatal("wiki2html: %r");
		write(1, s_to_c(h), s_len(h));
	}
	exits(0);
}
Beispiel #4
0
/* send message filtering Reply-to out of messages */
void
printmsg(int fd, String *msg, char *replyto, char *listname)
{
	Field *f, *subject;
	Node *p;
	char *cp, *ocp;

	subject = nil;
	cp = s_to_c(msg);
	for(f = firstfield; f; f = f->next){
		ocp = cp;
		for(p = f->node; p; p = p->next)
			cp = p->end+1;
		if(f->node->c == REPLY_TO)
			continue;
		if(f->node->c == PRECEDENCE)
			continue;
		if(f->node->c == SUBJECT){
			subject = f;
			continue;
		}
		write(fd, ocp, cp-ocp);
	}
	printsubject(fd, subject, listname);
	fprint(fd, "Reply-To: %s\nPrecedence: bulk\n", replyto);
	write(fd, cp, s_len(msg) - (cp - s_to_c(msg)));
}
Beispiel #5
0
/* if the mailbox exists, cat the mail to the end of it */
void
appendtoarchive(char* listname, String *firstline, String *msg)
{
	String *mbox;
	int fd;

	mbox = s_new();
	mboxpath("mbox", listname, mbox, 0);
	if(access(s_to_c(mbox), 0) < 0)
		return;
	fd = open(s_to_c(mbox), OWRITE);
	if(fd < 0)
		return;
	s_append(msg, "\n");
	write(fd, s_to_c(firstline), s_len(firstline));
	write(fd, s_to_c(msg), s_len(msg));
}
Beispiel #6
0
char *RQ_GetHeader(ReqInfo *req, char *header)
{
  int len = array_len(req->headers), i;

  for (i=0; i<len/2; i++) {
    if (req->headers[i*2] && !strcncmp(req->headers[i*2], header, s_len(req->headers[i*2]), strlen(header)))
      return i*2+1 < len ? req->headers[i*2+1] : NULL;
  }

  return NULL;
}
Beispiel #7
0
/*
 *  walk up the tree building a Unix style path
 */
static void
unixpath(Node *node, String *path)
{
	if(node == node->parent){
		s_append(path, s_to_c(remrootpath));
		return;
	}
	unixpath(node->parent, path);
	if(s_len(path) > 0 && strcmp(s_to_c(path), "/") != 0)
		s_append(path, "/");
	s_append(path, s_to_c(node->remname));
}
Beispiel #8
0
/*
 *  walk up the tree building a MVS style path
 */
static void
mvspath(Node *node, String *path)
{
	if(node == node->parent){
		s_append(path, s_to_c(remrootpath));
		return;
	}
	mvspath(node->parent, path);
	if(s_len(path) > 0)
		s_append(path, ".");
	s_append(path, s_to_c(node->remname));
}
Beispiel #9
0
void
main(int argc, char **argv)
{
	int t;
	int parse;
	String *h;
	Whist *doc;

	rfork(RFNAMEG);

	t = Tpage;
	ARGBEGIN{
	default:
		usage();
	case 'd':
		wikidir = EARGF(usage());
		break;
	case 'h':
		t = Thistory;
		break;
	case 'o':
		t = Toldpage;
		break;
	case 'D':
		t = Tdiff;
		break;
	case 'P':
		parse = 1;
	}ARGEND

	if(argc != 1)
		usage();

	if(t == Thistory || t==Tdiff)
		doc = gethistory(atoi(argv[0]));
	else
		doc = getcurrent(atoi(argv[0]));

	if(doc == nil)
		sysfatal("doc: %r");

	if(parse){
		printpage(doc->doc->wtxt);
		exits(0);
	}
	if((h = tohtml(doc, doc->doc+doc->ndoc-1, t)) == nil)
		sysfatal("wiki2html: %r");

	write(1, s_to_c(h), s_len(h));
	exits(0);
}
Beispiel #10
0
Datei: lex.c Projekt: lufia/wf
static int
readstr(char *delim, char *s, int allow0)
{
	int r;

	r = rreadstr(delim, s);
	if(r == Terror)
		return r;
	if(!allow0 && s_len(sbuf) == 0){
		yyerror("empty string");
		return Terror;
	}
	return r;
}
Beispiel #11
0
/*
 *  get a line that ends in crnl or cr, turn terminating crnl into a nl
 *
 *  return 0 on EOF
 */
static int
getcrnl(String *s, Biobuf *fp)
{
	int c;

	for(;;){
		c = Bgetc(fp);
		if(debug) {
			seek(2, 0, 2);
			fprint(2, "%c", c);
		}
		switch(c){
		case 0:
			break;
		case -1:
			goto out;
		case '\r':
			c = Bgetc(fp);
			if(c == '\n'){
				if(debug) {
					seek(2, 0, 2);
					fprint(2, "%c", c);
					stamp();
				}
				s_putc(s, '\n');
				goto out;
			}
			Bungetc(fp);
			s_putc(s, '\r');
			break;
		case '\n':
			s_putc(s, c);
			goto out;
		default:
			s_putc(s, c);
			break;
		}
	}
out:
	s_terminate(s);
	return s_len(s);
}
Beispiel #12
0
Datei: lex.c Projekt: lufia/wf
static int
readname(char *s)
{
	int c;

	s_reset(sbuf);
	if(s)
		skip(s);
	while((c=GETC()) >= 0 && (isalnum(c) || c == '-'))
		s_putc(sbuf, c);
	if(c == Beof){
		yyerror("eof in id/class");
		return Terror;
	}
	UNGETC(c);
	if(s_len(sbuf) == 0){
		yyerror("empty name");
		return Terror;
	}
	s_terminate(sbuf);
	return Tstring;
}
Beispiel #13
0
String *
s_dec64(String *sin)
{
	int lin, lout;
	String *sout;

	lin = s_len(sin);

	/*
	 * if the string is coming from smtpd.y, it will have no nl.
	 * if it is coming from getcrnl below, it will have an nl.
	 */
	if (*(s_to_c(sin)+lin-1) == '\n')
		lin--;
	sout = s_newalloc(lin+1);
	lout = dec64((uchar *)s_to_c(sout), lin, s_to_c(sin), lin);
	if (lout < 0) {
		s_free(sout);
		return nil;
	}
	sout->ptr = sout->base + lout;
	s_terminate(sout);
	return sout;
}
Beispiel #14
0
void iconv(const char* to_charset, const char* from_charset, std::string& target, const std::string& source) throw (std::runtime_error)
{
  iconv_t cd(::iconv_open(to_charset, from_charset));
  if (cd == reinterpret_cast<iconv_t>(-1) )
    throw std::runtime_error("iconv_open failed");
  size_t s_len(source.size());
  char* s_ptr(const_cast<char*>(source.data()));
  size_t max_o_len = s_len * 5;
  size_t o_len(max_o_len);
  char* const buf = new char[o_len];
  char* o_ptr(buf);
  ::iconv(cd, &s_ptr, &s_len, &o_ptr, &o_len);
//  if ((s_len != 0) || errno) {
//    int sys_err(errno);
 //   throw std::runtime_error(std::string(source) +
//			     ": Dv::Xml::iconv from " + from_charset + " to " + to_charset + " failed [" +
//			     (sys_err ? strerror(sys_err) : "") + "]"
//			     );
//  }
  target.resize(0);
  target.append(buf, max_o_len - o_len);
  delete [] buf;
  iconv_close(cd);
}
Beispiel #15
0
/*
 * Attempt to install a new page.  If t==0 we are creating.
 * Otherwise, we are editing and t must be set to the current
 * version (t is the version we started with) to avoid conflicting
 * writes.
 *
 * If there is a conflicting write, we still write the page to 
 * the history file, but mark it as a failed write.
 */
int
writepage(int num, uint32_t t, String *s, char *title)
{
	char tmp[40], tmplock[40], err[ERRMAX], hist[40], *p;
	int conflict, lfd, fd;
	Biobuf *b;
	String *os;

	sprint(tmp, "d/%d", num);
	sprint(tmplock, "d/L.%d", num);
	sprint(hist, "d/%d.hist", num);
	if((lfd = getlock(tmplock)) < 0)
		return -1;

	conflict = 0;
	if(b = wBopen(tmp, OREAD)){
		Brdline(b, '\n');	/* title */
		if(p = Brdline(b, '\n'))		/* version */
			p[Blinelen(b)-1] = '\0';
		if(p==nil || p[0] != 'D'){
			snprint(err, sizeof err, "bad format in extant file");
			conflict = 1;
		}else if(strtoul(p+1, 0, 0) != t){
			os = Brdstring(b);	/* why read the whole file? */
			p = strchr(s_to_c(s), '\n');
			if(p!=nil && strcmp(p+1, s_to_c(os))==0){	/* ignore dup write */
				close(lfd);
				s_free(os);
				Bterm(b);
				return 0;
			}
			s_free(os);
			snprint(err, sizeof err, "update conflict %lud != %s", t, p+1);
			conflict = 1;
		}
		Bterm(b);
	}else{
		if(t != 0){
			close(lfd);
			werrstr("did not expect to create");
			return -1;
		}
	}

	if((fd = wopen(hist, OWRITE)) < 0){
		if((fd = wcreate(hist, OWRITE, 0666)) < 0){
			close(lfd);
			return -1;
		}else
			fprint(fd, "%s\n", title);
	}
	if(seek(fd, 0, 2) < 0
	|| (conflict && write(fd, "X\n", 2) != 2)
	|| write(fd, s_to_c(s), s_len(s)) != s_len(s)){
		close(fd);
		close(lfd);
		return -1;
	}
	close(fd);

	if(conflict){
		close(lfd);
		voidcache(num);
		werrstr(err);
		return -1;
	}

	if((fd = wcreate(tmp, OWRITE, 0666)) < 0){
		close(lfd);
		voidcache(num);
		return -1;
	}
	if(write(fd, title, strlen(title)) != strlen(title)
	|| write(fd, "\n", 1) != 1
	|| write(fd, s_to_c(s), s_len(s)) != s_len(s)){
		close(fd);
		close(lfd);
		voidcache(num);
		return -1;
	}
	close(fd);
	close(lfd);
	voidcache(num);
	return 0;
}
Beispiel #16
0
void		ft_putstr(char *s)
{
	write(1, s, s_len(s));
}
Beispiel #17
0
/* fix 822 addresses */
static void
rfc822cruft(message *mp)
{
	Field *f;
	Node *p;
	String *body, *s;
	char *cp;

	/*
	 *  parse headers in in-core part
	 */
	yyinit(s_to_c(mp->body), s_len(mp->body));
	mp->rfc822headers = 0;
	yyparse();
	mp->rfc822headers = 1;
	mp->received = received;

	/*
	 *  remove equivalent systems in all addresses
	 */
	body = s_new();
	cp = s_to_c(mp->body);
	for(f = firstfield; f; f = f->next){
		if(f->node->c == MIMEVERSION)
			mp->havemime = 1;
		if(f->node->c == FROM)
			mp->havefrom = getaddr(f->node);
		if(f->node->c == SENDER)
			mp->havesender = getaddr(f->node);
		if(f->node->c == REPLY_TO)
			mp->havereplyto = getaddr(f->node);
		if(f->node->c == TO)
			mp->haveto = 1;
		if(f->node->c == DATE)
			mp->havedate = 1;
		if(f->node->c == SUBJECT)
			mp->havesubject = getstring(f->node);
		if(f->node->c == PRECEDENCE && f->node->next && f->node->next->next){
			s = f->node->next->next->s;
			if(s && (strcmp(s_to_c(s), "bulk") == 0
				|| strcmp(s_to_c(s), "Bulk") == 0))
					mp->bulk = 1;
		}
		for(p = f->node; p; p = p->next){
			if(p->s){
				if(p->addr){
					cp = skipequiv(s_to_c(p->s));
					s_append(body, cp);
				} else 
					s_append(body, s_to_c(p->s));
			}else{
				s_putc(body, p->c);
				s_terminate(body);
			}
			if(p->white)
				s_append(body, s_to_c(p->white));
			cp = p->end+1;
		}
		s_append(body, "\n");
	}

	if(*s_to_c(body) == 0){
		s_free(body);
		return;
	}

	if(*cp != '\n')
		s_append(body, "\n");
	s_memappend(body, cp, s_len(mp->body) - (cp - s_to_c(mp->body)));
	s_terminate(body);

	firstfield = 0;
	mp->size += s_len(body) - s_len(mp->body);
	s_free(mp->body);
	mp->body = body;
}
Beispiel #18
0
void
main(int argc, char **argv)
{
	String *msg;
	String *firstline;
	char *listname, *alfile;
	Waitmsg *w;
	int fd;
	char *replytoname = nil;

	ARGBEGIN{
	case 'r':
		replytoname = ARGF();
		break;
	}ARGEND;

	rfork(RFENVG|RFREND);

	if(argc < 2)
		usage();
	alfile = argv[0];
	listname = argv[1];
	if(replytoname == nil)
		replytoname = listname;

	readaddrs(alfile);

	if(Binit(&in, 0, OREAD) < 0)
		sysfatal("opening input: %r");

	msg = s_new();
	firstline = s_new();

	/* discard the 'From ' line */
	if(s_read_line(&in, firstline) == nil)
		sysfatal("reading input: %r");

	/* read up to the first 128k of the message.  more is ridiculous. 
	     Not if word documents are distributed.  Upped it to 2MB (pb) */
	if(s_read(&in, msg, 2*1024*1024) <= 0)
		sysfatal("reading input: %r");

	/* parse the header */
	yyinit(s_to_c(msg), s_len(msg));
	yyparse();

	/* get the sender */
	getaddrs();
	if(from == nil)
		from = sender;
	if(from == nil)
		sysfatal("message must contain From: or Sender:");
	if(strcmp(listname, s_to_c(from)) == 0)
		sysfatal("can't remail messages from myself");
	addaddr(s_to_c(from));

	/* start the mailer up and return a pipe to it */
	fd = startmailer(listname);

	/* send message adding our own reply-to and precedence */
	printmsg(fd, msg, replytoname, listname);
	close(fd);

	/* wait for mailer to end */
	while(w = wait()){
		if(w->msg != nil && w->msg[0])
			sysfatal("%s", w->msg);
		free(w);
	}

	/* if the mailbox exists, cat the mail to the end of it */
	appendtoarchive(listname, firstline, msg);
	exits(0);
}
Beispiel #19
0
int compare_str(char *wildcard, char *check) {
	printf("===================================\nTesting with %s and %s\n", wildcard, check);
	char *wc = wildcard;
	int i; // get the position of the substring
	char substr[MAX_WILDCARD];
	int escape = 0;
	for (i = 0; *wc != '\0'; i++, wc++) {
		if (*wc == '*' && *(wc-1) != '\\') {
			break;
		}
		substr[i] = *wc;
	}	
	substr[i++] = '\0';

	// check if *wc is now '\0', because that means that no '*' was found
	if (*wc == '\0') {
		printf("Couldn't find any asterisk\n===============================================\n");
		return 0;
	}
	/*
	 * If code below runs well, then the beginning of check and wildcard match
	 */
	//printf("substr: %s\n", substr);
	char *ch = check;
	for (int j = 0; j < i-1; j++) {
		if (*(ch+j) != substr[j])
			return 0;
	}

	//printf("matching substr: %s\n", substr);
	// if it returned 0, then the string is not a substring of the wildcard
	// so, if the program still runs, we are at position i (where the * is)
	// and now we have to check if there is any string in place of the asterisk

	ch = wildcard + i;
	int j;
	for (j = 0; *ch != '\0'; j++, ch++)
		substr[j] = *ch;
	substr[j] = '\0';
	
	// now we should have a new substr
	char ast[100];
	// so now we have the last characters after the asterisk in substr
	ch = check + i - 1;

	int subl = s_len(substr);
	int subp = s_len(ch);
//	printf("subl: %i | subp: %i\n", subl, subp);
	for (j = 0; *ch != '\0'; ch++, j++, subp--) {
	//printf("subl: %i | subp: %i\n", subl, subp);
		if (subp <= subl) {
			if(str_eq(ch, substr)) {

	//	printf("Calling str_eq with %p and %s\n", ch, substr);
				ast[j] = '\0';
				printf("Hey, that's valid!\nInstead of the asterisk in %s we have %s\n=============================\n", wildcard, ast);
				return 1;
			}
		}
		ast[j] = *ch;
		
	}
	ast[j] = '\0';

//	printf("ast: %s\n", ast);
	printf("Sorry, but the strings don't match\n===========================================\n");
	return 0;
}
Beispiel #20
0
/*
 *  pipe message to mailer with the following transformations:
 *	- change \r\n into \n.
 *	- add sender's domain to any addrs with no domain
 *	- add a From: if none of From:, Sender:, or Replyto: exists
 *	- add a Received: line
 */
int
pipemsg(int *byteswritten)
{
	int n, nbytes, sawdot, status, nonhdr, bpr;
	char *cp;
	Field *f;
	Link *l;
	Node *p;
	String *hdr, *line;

	pipesig(&status);	/* set status to 1 on write to closed pipe */
	sawdot = 0;
	status = 0;

	/*
	 *  add a 'From ' line as envelope
	 */
	nbytes = 0;
	nbytes += Bprint(pp->std[0]->fp, "From %s %s remote from \n",
		s_to_c(senders.first->p), thedate());

	/*
	 *  add our own Received: stamp
	 */
	nbytes += Bprint(pp->std[0]->fp, "Received: from %s ", him);
	if(nci->rsys)
		nbytes += Bprint(pp->std[0]->fp, "([%s]) ", nci->rsys);
	nbytes += Bprint(pp->std[0]->fp, "by %s; %s\n", me, thedate());

	/*
	 *  read first 16k obeying '.' escape.  we're assuming
	 *  the header will all be there.
	 */
	line = s_new();
	hdr = s_new();
	while(sawdot == 0 && s_len(hdr) < 16*1024){
		n = getcrnl(s_reset(line), &bin);

		/* eof or error ends the message */
		if(n <= 0)
			break;

		/* a line with only a '.' ends the message */
		cp = s_to_c(line);
		if(n == 2 && *cp == '.' && *(cp+1) == '\n'){
			sawdot = 1;
			break;
		}

		s_append(hdr, *cp == '.' ? cp+1 : cp);
	}

	/*
	 *  parse header
	 */
	yyinit(s_to_c(hdr), s_len(hdr));
	yyparse();

	/*
	 *  Look for masquerades.  Let Sender: trump From: to allow mailing list
	 *  forwarded messages.
	 */
	if(fflag)
		nbytes += forgedheaderwarnings();

	/*
	 *  add an orginator and/or destination if either is missing
	 */
	if(originator == 0){
		if(senders.last == nil || senders.last->p == nil)
			nbytes += Bprint(pp->std[0]->fp, "From: /dev/null@%s\n",
				him);
		else
			nbytes += Bprint(pp->std[0]->fp, "From: %s\n",
				s_to_c(senders.last->p));
	}
	if(destination == 0){
		nbytes += Bprint(pp->std[0]->fp, "To: ");
		for(l = rcvers.first; l; l = l->next){
			if(l != rcvers.first)
				nbytes += Bprint(pp->std[0]->fp, ", ");
			nbytes += Bprint(pp->std[0]->fp, "%s", s_to_c(l->p));
		}
		nbytes += Bprint(pp->std[0]->fp, "\n");
	}

	/*
	 *  add sender's domain to any domainless addresses
	 *  (to avoid forging local addresses)
	 */
	cp = s_to_c(hdr);
	for(f = firstfield; cp != nil && f; f = f->next){
		for(p = f->node; cp != 0 && p; p = p->next) {
			bpr = 0;
			cp = bprintnode(pp->std[0]->fp, p, &bpr);
			nbytes += bpr;
		}
		if(status == 0 && Bprint(pp->std[0]->fp, "\n") < 0){
			piperror = "write error";
			status = 1;
		}
		nbytes++;		/* for newline */
	}
	if(cp == nil){
		piperror = "sender domain";
		status = 1;
	}

	/* write anything we read following the header */
	nonhdr = s_to_c(hdr) + s_len(hdr) - cp;
	if(status == 0 && Bwrite(pp->std[0]->fp, cp, nonhdr) < 0){
		piperror = "write error 2";
		status = 1;
	}
	nbytes += nonhdr;
	s_free(hdr);

	/*
	 *  pass rest of message to mailer.  take care of '.'
	 *  escapes.
	 */
	while(sawdot == 0){
		n = getcrnl(s_reset(line), &bin);

		/* eof or error ends the message */
		if(n <= 0)
			break;

		/* a line with only a '.' ends the message */
		cp = s_to_c(line);
		if(n == 2 && *cp == '.' && *(cp+1) == '\n'){
			sawdot = 1;
			break;
		}
		if(cp[0] == '.'){
			cp++;
			n--;
		}
		nbytes += n;
		if(status == 0 && Bwrite(pp->std[0]->fp, cp, n) < 0){
			piperror = "write error 3";
			status = 1;
		}
	}
	s_free(line);
	if(sawdot == 0){
		/* message did not terminate normally */
		snprint(pipbuf, sizeof pipbuf, "network eof: %r");
		piperror = pipbuf;
		if (pp->pid > 0) {
			syskillpg(pp->pid);
			/* none can't syskillpg, so try a variant */
			sleep(500);
			syskill(pp->pid);
		}
		status = 1;
	}

	if(status == 0 && Bflush(pp->std[0]->fp) < 0){
		piperror = "write error 4";
		status = 1;
	}
	if (debug) {
		stamp();
		fprint(2, "at end of message; %s .\n",
			(sawdot? "saw": "didn't see"));
	}
	stream_free(pp->std[0]);
	pp->std[0] = 0;
	*byteswritten = nbytes;
	pipesigoff();
	if(status && !piperror)
		piperror = "write on closed pipe";
	return status;
}
Beispiel #21
0
void
auth(String *mech, String *resp)
{
	char *user, *pass, *scratch = nil;
	AuthInfo *ai = nil;
	Chalstate *chs = nil;
	String *s_resp1_64 = nil, *s_resp2_64 = nil, *s_resp1 = nil;
	String *s_resp2 = nil;

	if (rejectcheck())
		goto bomb_out;

	syslog(0, "smtpd", "auth(%s, %s) from %s", s_to_c(mech),
		"(protected)", him);

	if (authenticated) {
	bad_sequence:
		rejectcount++;
		reply("503 5.5.2 Bad sequence of commands\r\n");
		goto bomb_out;
	}
	if (cistrcmp(s_to_c(mech), "plain") == 0) {
		if (!passwordinclear) {
			rejectcount++;
			reply("538 5.7.1 Encryption required for requested "
				"authentication mechanism\r\n");
			goto bomb_out;
		}
		s_resp1_64 = resp;
		if (s_resp1_64 == nil) {
			reply("334 \r\n");
			s_resp1_64 = s_new();
			if (getcrnl(s_resp1_64, &bin) <= 0)
				goto bad_sequence;
		}
		s_resp1 = s_dec64(s_resp1_64);
		if (s_resp1 == nil) {
			rejectcount++;
			reply("501 5.5.4 Cannot decode base64\r\n");
			goto bomb_out;
		}
		memset(s_to_c(s_resp1_64), 'X', s_len(s_resp1_64));
		user = s_to_c(s_resp1) + strlen(s_to_c(s_resp1)) + 1;
		pass = user + strlen(user) + 1;
		ai = auth_userpasswd(user, pass);
		authenticated = ai != nil;
		memset(pass, 'X', strlen(pass));
		goto windup;
	}
	else if (cistrcmp(s_to_c(mech), "login") == 0) {
		if (!passwordinclear) {
			rejectcount++;
			reply("538 5.7.1 Encryption required for requested "
				"authentication mechanism\r\n");
			goto bomb_out;
		}
		if (resp == nil) {
			reply("334 VXNlcm5hbWU6\r\n");
			s_resp1_64 = s_new();
			if (getcrnl(s_resp1_64, &bin) <= 0)
				goto bad_sequence;
		}
		reply("334 UGFzc3dvcmQ6\r\n");
		s_resp2_64 = s_new();
		if (getcrnl(s_resp2_64, &bin) <= 0)
			goto bad_sequence;
		s_resp1 = s_dec64(s_resp1_64);
		s_resp2 = s_dec64(s_resp2_64);
		memset(s_to_c(s_resp2_64), 'X', s_len(s_resp2_64));
		if (s_resp1 == nil || s_resp2 == nil) {
			rejectcount++;
			reply("501 5.5.4 Cannot decode base64\r\n");
			goto bomb_out;
		}
		ai = auth_userpasswd(s_to_c(s_resp1), s_to_c(s_resp2));
		authenticated = ai != nil;
		memset(s_to_c(s_resp2), 'X', s_len(s_resp2));
windup:
		if (authenticated) {
			/* if you authenticated, we trust you despite your IP */
			trusted = 1;
			reply("235 2.0.0 Authentication successful\r\n");
		} else {
			rejectcount++;
			reply("535 5.7.1 Authentication failed\r\n");
			syslog(0, "smtpd", "authentication failed: %r");
		}
		goto bomb_out;
	}
	else if (cistrcmp(s_to_c(mech), "cram-md5") == 0) {
		int chal64n;
		char *resp, *t;

		chs = auth_challenge("proto=cram role=server");
		if (chs == nil) {
			rejectcount++;
			reply("501 5.7.5 Couldn't get CRAM-MD5 challenge\r\n");
			goto bomb_out;
		}
		scratch = malloc(chs->nchal * 2 + 1);
		chal64n = enc64(scratch, chs->nchal * 2, (uchar *)chs->chal,
			chs->nchal);
		scratch[chal64n] = 0;
		reply("334 %s\r\n", scratch);
		s_resp1_64 = s_new();
		if (getcrnl(s_resp1_64, &bin) <= 0)
			goto bad_sequence;
		s_resp1 = s_dec64(s_resp1_64);
		if (s_resp1 == nil) {
			rejectcount++;
			reply("501 5.5.4 Cannot decode base64\r\n");
			goto bomb_out;
		}
		/* should be of form <user><space><response> */
		resp = s_to_c(s_resp1);
		t = strchr(resp, ' ');
		if (t == nil) {
			rejectcount++;
			reply("501 5.5.4 Poorly formed CRAM-MD5 response\r\n");
			goto bomb_out;
		}
		*t++ = 0;
		chs->user = resp;
		chs->resp = t;
		chs->nresp = strlen(t);
		ai = auth_response(chs);
		authenticated = ai != nil;
		goto windup;
	}
	rejectcount++;
	reply("501 5.5.1 Unrecognised authentication type %s\r\n", s_to_c(mech));
bomb_out:
	if (ai)
		auth_freeAI(ai);
	if (chs)
		auth_freechal(chs);
	if (scratch)
		free(scratch);
	if (s_resp1)
		s_free(s_resp1);
	if (s_resp2)
		s_free(s_resp2);
	if (s_resp1_64)
		s_free(s_resp1_64);
	if (s_resp2_64)
		s_free(s_resp2_64);
}