1 /*	$OpenBSD: iobuf.h,v 1.1 2012/01/29 00:32:51 eric Exp $	*/
2 /*
3  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/queue.h>
21 
22 #include <ctype.h>
23 #include <err.h>
24 #include <errno.h>
25 #include <getopt.h>
26 #include <netdb.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <vis.h>
33 
34 #include "iobuf.h"
35 
36 #include "smtpscript.h"
37 
38 void   *ssl_connect(int);
39 void	ssl_close(void *);
40 
41 /* XXX */
42 #define SMTP_LINE_MAX	4096
43 
44 enum {
45 	OP_BLOCK,
46 	OP_REPEAT,
47 	OP_RANDOM,
48 
49 	OP_NOOP,
50 
51 	OP_FAIL,
52 	OP_CALL,
53 	OP_CONNECT,
54 	OP_DISCONNECT,
55 	OP_STARTTLS,
56 	OP_SLEEP,
57 	OP_WRITE,
58 
59 	OP_EXPECT_DISCONNECT,
60 	OP_EXPECT_SMTP_RESPONSE,
61 };
62 
63 struct op {
64 	struct op	*next;
65 	int		 type;
66 	union {
67 		struct {
68 			int		 count;
69 			struct op	*start;
70 			struct op	*last;
71 		}	block;
72 		struct {
73 			struct op	*op;
74 			int		 count;
75 		}	repeat;
76 		struct {
77 			struct op	*block;
78 		}	random;
79 		struct {
80 			char		*reason;
81 		}	fail;
82 		struct {
83 			struct procedure *proc;
84 		}	call;
85 		struct {
86 			char		*hostname;
87 			int		 portno;
88 		}	connect;
89 		struct {
90 			unsigned int	 ms;
91 		}	sleep;
92 		struct {
93 			const void	*buf;
94 			size_t		 len;
95 		} write;
96 		struct {
97 			int		 flags;
98 		} expect_smtp;
99 	} u;
100 };
101 
102 #define RES_OK		0
103 #define RES_SKIP	1
104 #define RES_FAIL	2
105 #define RES_ERROR	3
106 
107 struct ctx {
108 	int		 sock;
109 	void		*ssl;
110 	struct iobuf	 iobuf;
111 	int		 lvl;
112 
113 	int		 result;
114 	char		*reason;
115 };
116 
117 static struct op	* _op_connect;
118 
119 int		verbose;
120 int		randomdelay; /* between each testcase */
121 int		tapout;
122 size_t		rundelay; /* between each testcase */
123 
124 static size_t	test_pass;
125 static size_t	test_skip;
126 static size_t	test_fail;
127 static size_t	test_error;
128 static size_t	test_total = 0;
129 
130 static struct op *op_add_child(struct op *, const struct op *);
131 static void run_testcase(struct procedure *);
132 static void print_testcase(char *status, char *name, char *reason, char *directive, size_t number);
133 static void process_op(struct ctx *, struct op *);
134 static const char * parse_smtp_response(char *, size_t, char **, int *);
135 
136 struct procedure *
procedure_create(struct script * scr,char * name)137 procedure_create(struct script *scr, char *name)
138 {
139 	struct procedure	*p;
140 
141 	if (procedure_get_by_name(scr, name)) {
142 		warnx("procedure \"%s\" already exists", name);
143 		return (NULL);
144 	}
145 
146 	p = calloc(1, sizeof *p);
147 	TAILQ_INIT(&p->vars);
148 	p->name = strdup(name);
149 
150 	TAILQ_INSERT_TAIL(&scr->procs, p, entry);
151 
152 	return (p);
153 }
154 
155 struct procedure *
procedure_get_by_name(struct script * scr,const char * name)156 procedure_get_by_name(struct script *scr, const char *name)
157 {
158 	struct procedure *p;
159 
160 	TAILQ_FOREACH(p, &scr->procs, entry)
161 		if (!strcmp(name, p->name))
162 			return (p);
163 
164 	return (NULL);
165 }
166 
167 int
proc_getvaridx(struct procedure * proc,char * name)168 proc_getvaridx(struct procedure *proc, char *name)
169 {
170 	struct variable	*v;
171 	int		 n;
172 
173 	n = 0;
174 	TAILQ_FOREACH(v, &proc->vars, entry) {
175 		if (!strcmp(name, v->name))
176 			return (n);
177 		n++;
178 	}
179 
180 	return (-1);
181 }
182 
183 int
proc_addvar(struct procedure * proc,char * name)184 proc_addvar(struct procedure *proc, char *name)
185 {
186 	struct variable	*v;
187 
188 	printf("adding variable \"%s\"\n", name);
189 
190 	if (proc_getvaridx(proc, name) != -1)
191 		return (-1);
192 	v = calloc(1, sizeof *v);
193 	v->name = name;
194 	TAILQ_INSERT_TAIL(&proc->vars, v, entry);
195 
196 	return (proc->varcount++);
197 }
198 
199 struct op *
op_block(struct op * parent)200 op_block(struct op *parent)
201 {
202 	struct op	o;
203 
204 	bzero(&o, sizeof o);
205 	o.type = OP_BLOCK;
206 
207 	return (op_add_child(parent, &o));
208 }
209 
210 struct op *
op_repeat(struct op * parent,int count,struct op * op)211 op_repeat(struct op *parent, int count, struct op *op)
212 {
213 	struct op	o;
214 
215 	bzero(&o, sizeof o);
216 	o.type = OP_REPEAT;
217 	o.u.repeat.count = count;
218 	o.u.repeat.op = op;
219 
220 	return (op_add_child(parent, &o));
221 }
222 
223 struct op *
op_random(struct op * parent,struct op * op)224 op_random(struct op *parent, struct op *op)
225 {
226 	struct op	o;
227 
228 	bzero(&o, sizeof o);
229 	o.type = OP_RANDOM;
230 	o.u.random.block = op;
231 
232 	return (op_add_child(parent, &o));
233 }
234 
235 struct op *
op_noop(struct op * parent)236 op_noop(struct op *parent)
237 {
238 	struct op	o;
239 
240 	bzero(&o, sizeof o);
241 	o.type = OP_NOOP;
242 
243 	return (op_add_child(parent, &o));
244 }
245 
246 struct op *
op_call(struct op * parent,struct procedure * proc)247 op_call(struct op *parent, struct procedure *proc)
248 {
249 	struct op	o;
250 
251 	bzero(&o, sizeof o);
252 	o.type = OP_CALL;
253 	o.u.call.proc = proc;
254 
255 	return (op_add_child(parent, &o));
256 }
257 
258 struct op *
op_fail(struct op * parent,char * reason)259 op_fail(struct op *parent, char *reason)
260 {
261 	struct op	o;
262 
263 	bzero(&o, sizeof o);
264 	o.type = OP_FAIL;
265 	o.u.fail.reason = reason;
266 
267 	return (op_add_child(parent, &o));
268 }
269 
270 struct op *
op_connect(struct op * parent,const char * hostname,int portno)271 op_connect(struct op *parent, const char *hostname, int portno)
272 {
273 	struct op	o;
274 
275 	bzero(&o, sizeof o);
276 	o.type = OP_CONNECT;
277 	o.u.connect.hostname = strdup(hostname);
278 	o.u.connect.portno = portno;
279 	return (op_add_child(parent, &o));
280 }
281 
282 struct op *
op_disconnect(struct op * parent)283 op_disconnect(struct op *parent)
284 {
285 	struct op	o;
286 
287 	bzero(&o, sizeof o);
288 	o.type	= OP_DISCONNECT;
289 	return (op_add_child(parent, &o));
290 }
291 
292 struct op *
op_starttls(struct op * parent)293 op_starttls(struct op *parent)
294 {
295 	struct op	o;
296 
297 	bzero(&o, sizeof o);
298 	o.type	= OP_STARTTLS;
299 	return (op_add_child(parent, &o));
300 }
301 
302 struct op *
op_sleep(struct op * parent,unsigned int ms)303 op_sleep(struct op *parent, unsigned int ms)
304 {
305 	struct op	o;
306 
307 	bzero(&o, sizeof o);
308 	o.type	= OP_SLEEP;
309 	o.u.sleep.ms = ms;
310 	return (op_add_child(parent, &o));
311 }
312 
313 struct op *
op_write(struct op * parent,const void * buf,size_t len)314 op_write(struct op *parent, const void *buf, size_t len)
315 {
316 	struct op	o;
317 
318 	bzero(&o, sizeof o);
319 	o.type	= OP_WRITE;
320 	o.u.write.buf = buf;
321 	o.u.write.len = len;
322 	return (op_add_child(parent, &o));
323 }
324 
325 struct op *
op_printf(struct op * parent,const char * fmt,...)326 op_printf(struct op *parent, const char *fmt, ...)
327 {
328 	va_list		 ap;
329 	char		*buf;
330 	int		 len;
331 
332 	va_start(ap, fmt);
333 	if ((len = vasprintf(&buf, fmt, ap)) == -1)
334 		err(1, "vasprintf");
335 	va_end(ap);
336 
337 	return op_write(parent, buf, len);
338 }
339 
340 struct op *
op_expect_disconnect(struct op * parent)341 op_expect_disconnect(struct op *parent)
342 {
343 	struct op	o;
344 
345 	bzero(&o, sizeof o);
346 	o.type	= OP_EXPECT_DISCONNECT;
347 	return (op_add_child(parent, &o));
348 }
349 
350 struct op *
op_expect_smtp_response(struct op * parent,int flags)351 op_expect_smtp_response(struct op *parent, int flags)
352 {
353 	struct op	o;
354 
355 	bzero(&o, sizeof o);
356 	o.type	= OP_EXPECT_SMTP_RESPONSE;
357 	o.u.expect_smtp.flags = flags;
358 	return (op_add_child(parent, &o));
359 }
360 
361 static void
usage(void)362 usage(void)
363 {
364 	extern const char *__progname;
365 	errx(1, "Usage: %s [-rvt] [-d delay] script", __progname);
366 }
367 
368 int
main(int argc,char ** argv)369 main(int argc, char **argv)
370 {
371 	struct script		*s;
372 	struct procedure	*p;
373 	int			 ch;
374 
375 	while ((ch = getopt(argc, argv, "d:rvt")) != -1) {
376 		switch(ch) {
377 		case 'v':
378 			verbose += 1;
379 			break;
380 		case 'd':
381 			rundelay = atoi(optarg) * 1000;
382 			break;
383 		case 'r':
384 			randomdelay = 1;
385 			break;
386 		case 't':
387 			tapout = 1;
388 			break;
389 		default:
390 			usage();
391 			/* NOTREACHED */
392 		}
393 	}
394 	argc -= optind;
395 	argv += optind;
396 
397 	if (argc != 1)
398 		usage();
399 
400 	s = parse_script(argv[0]);
401 	if (s == NULL)
402 		errx(1, "error reading script file");
403 
404 	_op_connect = op_connect(NULL, "127.0.0.1", 25);
405 
406 	if (tapout) {
407 		printf("# smtpscript is an SMTP testing framework\n\n");
408 		printf("TAP version 13\n");
409 	}
410 
411 	TAILQ_FOREACH(p, &s->procs, entry)
412 		if (p->flags & PROC_TESTCASE)
413 			run_testcase(p);
414 
415 	if (tapout)
416 		printf("1..%zu\n", test_total);
417 	else {
418 		printf("passed: %zu/%zu (skipped: %zu, failed: %zu, error: %zu)\n",
419 		test_pass,
420 		test_total,
421 		test_skip,
422 		test_fail,
423 		test_error);
424 	}
425 	return (0);
426 }
427 
428 static struct op *
op_add_child(struct op * parent,const struct op * op)429 op_add_child(struct op *parent, const struct op *op)
430 {
431 	struct op	*n;
432 
433 	n = malloc(sizeof *n);
434 	if (n == NULL)
435 		err(1, "malloc");
436 
437 	memmove(n, op, sizeof *n);
438 	n->next = NULL;
439 
440 	/* printf("op:%p type:%i parent: %p\n", n, n->type, parent); */
441 
442 	if (parent) {
443 		if (parent->u.block.start == NULL)
444 			parent->u.block.start = n;
445 		if (parent->u.block.last)
446 			parent->u.block.last->next = n;
447 		parent->u.block.last = n;
448 		parent->u.block.count += 1;
449 	}
450 
451 	return (n);
452 }
453 
454 static void
run_testcase(struct procedure * proc)455 run_testcase(struct procedure *proc)
456 {
457 	struct ctx	 c;
458 	uint32_t	 rdelay;
459 
460 	bzero(&c, sizeof c);
461 	c.sock = -1;
462 	c.lvl = 1;
463 
464 	if (rundelay) {
465 		if (randomdelay)
466 			rdelay = arc4random_uniform(rundelay);
467 		else
468 			rdelay = rundelay;
469 		usleep(rdelay);
470 	}
471 
472 	fflush(stdout);
473 
474 	if (verbose > 1)
475 		printf("\n");
476 
477 	if (!(proc->flags & PROC_NOCONNECT))
478 		process_op(&c, _op_connect);
479 	process_op(&c, proc->root);
480 
481 	if (c.sock != -1)
482 		close(c.sock);
483 	if (c.ssl)
484 		ssl_close(c.ssl);
485 	iobuf_clear(&c.iobuf);
486 
487 	if (verbose > 1) {
488 		printf("# Done with test-case \"%s\": ", proc->name);
489 	}
490 
491 	switch (c.result) {
492 	case RES_OK:
493 		test_total += 1;
494 		if (proc->flags & PROC_EXPECTFAIL) {
495 			print_testcase("not ok", proc->name, c.reason, "TODO", test_total); // XPass
496 			test_fail += 1;
497 		} else if (proc->flags & PROC_SKIP) {
498 			test_skip += 1;
499 			print_testcase("ok", proc->name, c.reason, "SKIP", test_total);
500 		}
501 		else {
502 			print_testcase("ok", proc->name, c.reason, NULL, test_total);
503 			test_pass += 1;
504 		}
505 
506 		break;
507 
508 	case RES_SKIP:
509 		test_skip += 1;
510 		test_total += 1;
511 		print_testcase("not ok", proc->name, c.reason, "SKIP", test_total);
512 		break;
513 
514 	case RES_FAIL:
515 		test_total += 1;
516 		if (proc->flags & PROC_EXPECTFAIL) {
517 			print_testcase("not ok", proc->name, c.reason, "TODO", test_total); // XFail
518 			test_pass += 1;
519                 } else if (proc->flags & PROC_SKIP) {
520                         test_skip += 1;
521                         print_testcase("ok", proc->name, c.reason, "SKIP", test_total);
522                 }
523 		else {
524 			print_testcase("not ok", proc->name, c.reason, NULL, test_total);
525 			test_fail += 1;
526 		}
527 
528 		break;
529 
530 	case RES_ERROR:
531 		test_error += 1;
532 		test_total += 1;
533 		print_testcase("not ok", proc->name, c.reason, NULL, test_total);
534 		break;
535 	}
536 
537 	if (verbose > 1) {
538 		printf("\n");
539 	}
540 
541 }
542 
print_testcase(char * status,char * name,char * reason,char * directive,size_t number)543 void print_testcase(char *status, char *name, char *reason, char *directive, size_t number)
544 {
545 	printf("%s %zu", status, number);
546 	if (directive)
547 		printf(" - %s # %s\n", name, directive);
548 	else
549 		if (reason)
550 			printf(" - %s # %s\n", name, reason);
551 		else
552 			printf(" - %s\n", name);
553 }
554 
555 static size_t
strvisx2(char * dst,const char * src,size_t srclen,int flag)556 strvisx2(char *dst, const char *src, size_t srclen, int flag)
557 {
558 	size_t n, r, i;
559 
560 	n = strvisx(dst, src, srclen, flag);
561 	if (n == 0)
562 		return (0);
563 
564 	r = n;
565 	for (i = n - 1; i; i--) {
566 		if (dst[i] == '\r') {
567 			memmove(dst + i + 2, dst + i + 1, n + 1 - i);
568 			dst[i+1] = 'r';
569 			dst[i] = '\\';
570 			r++;
571 		} else if (dst[i] == '"') {
572 			memmove(dst + i + 2, dst + i + 1, n + 1 - i);
573 			dst[i+1] = '"';
574 			dst[i] = '\\';
575 			r++;
576 		}
577 	}
578 
579 	return (r);
580 }
581 
582 static const char *
show_data(const char * src,size_t len,size_t max)583 show_data(const char *src, size_t len, size_t max)
584 {
585 	static char	buf[8192 + 3];
586 	char		tmp[256];
587 	size_t		l, n;
588 
589 	l = len;
590 	if (len > 2048)
591 		l = 2048;
592 
593 	buf[0] = '"';
594 	n = strvisx2(&buf[1], src, l, VIS_SAFE | VIS_NL | VIS_TAB | VIS_CSTYLE);
595 	if (n >= max) {
596 		snprintf(tmp, sizeof tmp, "...\" [%zu]", l);
597 		buf[max - strlen(tmp)] = '\0';
598 		strlcat(buf, tmp, sizeof(buf));
599 	} else {
600 		strlcat(buf, "\"", sizeof(buf));
601 	}
602 
603 	return (buf);
604 }
605 
606 static void
print_op(struct op * op,int lvl)607 print_op(struct op *op, int lvl)
608 {
609 
610 
611 	if (op->type == OP_BLOCK)
612 		return;
613 
614 	while (lvl--)
615 		printf("  ");
616 
617 	switch(op->type) {
618 
619 	case OP_REPEAT:
620 		printf("=> repeat: %i\n", op->u.repeat.count);
621 		break;
622 
623 	case OP_RANDOM:
624 		printf("=> random: %i\n", op->u.random.block->u.block.count);
625 		break;
626 
627 	case OP_NOOP:
628 		printf("=> noop\n");
629 		break;
630 
631 	case OP_FAIL:
632 		printf("=> fail: %s\n", op->u.fail.reason);
633 		break;
634 
635 	case OP_CALL:
636 		printf("=> call: %s\n", op->u.call.proc->name);
637 		break;
638 
639 	case OP_CONNECT:
640 		printf("=> connect %s:%i\n",
641 		    op->u.connect.hostname,
642 		    op->u.connect.portno);
643 		break;
644 
645 	case OP_DISCONNECT:
646 		printf("=> disconnect\n");
647 		break;
648 
649 	case OP_STARTTLS:
650 		printf("=> starttls\n");
651 		break;
652 
653 	case OP_SLEEP:
654 		printf("=> sleep %ims\n", op->u.sleep.ms);
655 		break;
656 
657 	case OP_WRITE:
658 		printf("=> write %s\n",
659 		    show_data(op->u.write.buf, op->u.write.len, 70));
660 		break;
661 
662 	case OP_EXPECT_DISCONNECT:
663 		printf("<= disconnect\n");
664 		break;
665 
666 	case OP_EXPECT_SMTP_RESPONSE:
667 		printf("<= smtp-response 0x%04x\n", op->u.expect_smtp.flags);
668 		break;
669 
670 	default:
671 		printf("<> ??? %i;\n", op->type);
672 		break;
673 	}
674 }
675 
676 
677 static void
set_failure(struct ctx * ctx,int res,const char * fmt,...)678 set_failure(struct ctx *ctx, int res, const char *fmt, ...)
679 {
680 	va_list		 ap;
681 	int		 len;
682 
683 	ctx->result = res;
684 	va_start(ap, fmt);
685 	if ((len = vasprintf(&ctx->reason, fmt, ap)) == -1)
686 		err(1, "vasprintf");
687 	va_end(ap);
688 }
689 
690 static void
process_op(struct ctx * ctx,struct op * op)691 process_op(struct ctx *ctx, struct op *op)
692 {
693 	struct addrinfo	 hints, *a, *ai;
694 	struct op	*o;
695 	struct iobuf	*iobuf;
696 	int		 i, r, s, save_errno, cont;
697 	const char	*cause;
698 	char		 buf[16], *servname, *line;
699 	ssize_t		 n;
700 	size_t		 len;
701 	const char	*e;
702 
703 	if (verbose > 1)
704 		print_op(op, ctx->lvl);
705 
706 	iobuf = &ctx->iobuf;
707 
708 	switch(op->type) {
709 
710 	case OP_BLOCK:
711 		ctx->lvl += 1;
712 		for (o = op->u.block.start; o; o = o->next) {
713 			process_op(ctx, o);
714 			if (ctx->result)
715 				break;
716 		}
717 		ctx->lvl -= 1;
718 		break;
719 
720 	case OP_REPEAT:
721 		ctx->lvl += 1;
722 		for (i = 0; i < op->u.repeat.count; i++) {
723 			process_op(ctx, op->u.repeat.op);
724 			if (ctx->result)
725 				break;
726 		}
727 		ctx->lvl -= 1;
728 		break;
729 
730 	case OP_RANDOM:
731 
732 		if (op->u.random.block->u.block.count == 0)
733 			return;
734 
735 		ctx->lvl += 1;
736 
737 		i = arc4random_uniform(op->u.random.block->u.block.count);
738 		for (o = op->u.random.block->u.block.start; i; i--, o = o->next)
739 			;
740 		process_op(ctx, o);
741 		if (ctx->result)
742 			break;
743 		ctx->lvl -= 1;
744 		break;
745 
746 	case OP_NOOP:
747 		break;
748 
749 	case OP_FAIL:
750 		set_failure(ctx, RES_FAIL, op->u.fail.reason);
751 		break;
752 
753 	case OP_CALL:
754 		process_op(ctx, op->u.call.proc->root);
755 		break;
756 
757 	case OP_CONNECT:
758 		if (ctx->sock != -1)
759 			close(ctx->sock);
760 		ctx->sock = -1;
761 		iobuf_clear(iobuf);
762 
763 		servname = NULL;
764 		if (op->u.connect.portno) {
765 			snprintf(buf, sizeof buf, "%i", op->u.connect.portno);
766 			servname = buf;
767 		}
768 		bzero(&hints, sizeof hints);
769 		hints.ai_socktype = SOCK_STREAM;
770 		hints.ai_protocol = IPPROTO_TCP;
771 		r = getaddrinfo(op->u.connect.hostname, servname, &hints, &ai);
772 		if (r) {
773 			set_failure(ctx, RES_ERROR,
774 			    "failed to connect to %s:%s: %s",
775 			    op->u.connect.hostname, servname, gai_strerror(r));
776 			return;
777 		}
778 
779 		s = -1;
780 		for(a = ai; a; a = a->ai_next) {
781 			s = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
782 			if (s == -1) {
783 				cause = "socket";
784 				continue;
785 			}
786 			if (connect(s, a->ai_addr, a->ai_addrlen) == -1) {
787 				cause = "connect";
788 				save_errno = errno;
789 				close(s);
790 				errno = save_errno;
791 				s = -1;
792 				continue;
793 			}
794 			break;  /* okay we got one */
795 		}
796 		freeaddrinfo(ai);
797 		if (s == -1) {
798 			set_failure(ctx, RES_ERROR,
799 			    "failed to connect to %s:%s: %s",
800 			    op->u.connect.hostname, servname, cause);
801 		} else {
802 			ctx->sock = s;
803 			iobuf_init(iobuf, 0, 0);
804 		}
805 		break;
806 
807 	case OP_DISCONNECT:
808 		if (ctx->sock != -1)
809 			close(ctx->sock);
810 		ctx->sock = -1;
811 		iobuf_clear(iobuf);
812 		break;
813 
814 	case OP_STARTTLS:
815 		if (ctx->ssl)
816 			set_failure(ctx, RES_ERROR, "SSL context already here");
817 		else if ((ctx->ssl = ssl_connect(ctx->sock)) == NULL)
818 			set_failure(ctx, RES_ERROR, "SSL connection failed");
819 		break;
820 
821 	case OP_SLEEP:
822 		usleep(op->u.sleep.ms * 1000);
823 		break;
824 
825 	case OP_WRITE:
826 		iobuf_queue(iobuf, op->u.write.buf, op->u.write.len);
827 		if (ctx->ssl)
828 			r = iobuf_flush_ssl(iobuf, ctx->ssl);
829 		else
830 			r = iobuf_flush(iobuf, ctx->sock);
831 		switch (r) {
832 		case 0:
833 			break;
834 		case IOBUF_CLOSED:
835 			set_failure(ctx, RES_FAIL, "connection closed");
836 			break;
837 		case IOBUF_WANT_WRITE:
838 			set_failure(ctx, RES_ERROR, "iobuf_write(): WANT_WRITE");
839 			break;
840 		case IOBUF_ERROR:
841 			set_failure(ctx, RES_ERROR, "IO error");
842 			break;
843 		case IOBUF_SSLERROR:
844 			set_failure(ctx, RES_ERROR, "SSL error");
845 			break;
846 		default:
847 			set_failure(ctx, RES_ERROR, "iobuf_write(): bad value");
848 			break;
849 		}
850 		break;
851 
852 	case OP_EXPECT_DISCONNECT:
853 		if (iobuf_len(iobuf)) {
854 			set_failure(ctx, RES_ERROR, "%zu bytes of input left",
855 			    iobuf_len(iobuf));
856 			break;
857 		}
858 		if (ctx->ssl)
859 			n = iobuf_read_ssl(iobuf, ctx->ssl);
860 		else
861 			n = iobuf_read(iobuf, ctx->sock);
862 		switch (n) {
863 		case IOBUF_CLOSED:
864 			close(ctx->sock);
865 			ctx->sock = -1;
866 			if (ctx->ssl)
867 				ssl_close(ctx->ssl);
868 			break;
869 		case IOBUF_WANT_READ:
870 			set_failure(ctx, RES_ERROR, "iobuf_read(): WANT_READ");
871 			break;
872 		case IOBUF_ERROR:
873 			set_failure(ctx, RES_ERROR, "IO error");
874 			break;
875 		case IOBUF_SSLERROR:
876 			set_failure(ctx, RES_ERROR, "SSL error");
877 			break;
878 		default:
879 			set_failure(ctx, RES_FAIL, "data read: %s",
880 			    show_data(iobuf_data(iobuf), iobuf_len(iobuf), 70));
881 			break;
882 		}
883 		break;
884 
885 	case OP_EXPECT_SMTP_RESPONSE:
886 		line = NULL;
887 		while (1) {
888 			line = iobuf_getline(iobuf, &len);
889 			if (line) {
890 				e = parse_smtp_response(line, len, NULL, &cont);
891 				if (e) {
892 					set_failure(ctx, RES_FAIL, e);
893 					return;
894 				}
895 				if (!cont) {
896 					iobuf_normalize(iobuf);
897 					break;
898 				}
899 				if (!(op->u.expect_smtp.flags
900 				    & RESP_SMTP_MULTILINE)) {
901 					set_failure(ctx, RES_FAIL,
902 					   "single line response expected");
903 					return;
904 				}
905 				continue;
906 			}
907 
908 			if (iobuf_len(iobuf) >= SMTP_LINE_MAX) {
909 				set_failure(ctx, RES_FAIL, "line too long");
910 				return;
911 			}
912 
913 			iobuf_normalize(iobuf);
914 
915 		    again:
916 			if (ctx->ssl)
917 				n = iobuf_read_ssl(iobuf, ctx->ssl);
918 			else
919 				n = iobuf_read(iobuf, ctx->sock);
920 			switch (n) {
921 			case IOBUF_CLOSED:
922 				set_failure(ctx, RES_FAIL, "connection closed");
923 				return;
924 			case IOBUF_WANT_READ:
925 				goto again;
926 			case IOBUF_ERROR:
927 				set_failure(ctx, RES_ERROR, "io error");
928 				return;
929 			case IOBUF_SSLERROR:
930 				set_failure(ctx, RES_ERROR, "SSL error");
931 				return;
932 			default:
933 				break;
934 			}
935 		}
936 
937 		/* got our response */
938 
939 		if (verbose > 1) {
940 			len = ctx->lvl;
941 			while (len--)
942 				printf("  ");
943 			printf("   >>> %s\n", show_data(line, strlen(line), 70));
944 		}
945 
946 		switch (line[0]) {
947 		case '2':
948 		case '3':
949 			if (!(op->u.expect_smtp.flags & RESP_SMTP_OK))
950 				set_failure(ctx, RES_FAIL,
951 				    "unexpected response code0: %s", line);
952 			break;
953 		case '4':
954 			if (!(op->u.expect_smtp.flags & RESP_SMTP_TEMPFAIL))
955 				set_failure(ctx, RES_FAIL,
956 				    "unexpected response code1: %s", line);
957 			break;
958 		case '5':
959 			if (!(op->u.expect_smtp.flags & RESP_SMTP_PERMFAIL))
960 				set_failure(ctx, RES_FAIL,
961 				    "unexpected response code2: %s", line);
962 			break;
963 		default:
964 			set_failure(ctx, RES_FAIL,
965 				    "unexpected response code???: %s", line);
966 			break;
967 		}
968 		break;
969 
970 	default:
971 		ctx->result = RES_ERROR;
972 		ctx->reason = "invalid operator";
973 		break;
974 	}
975 }
976 
977 static const char *
parse_smtp_response(char * line,size_t len,char ** msg,int * cont)978 parse_smtp_response(char *line, size_t len, char **msg, int *cont)
979 {
980 	size_t	 i;
981 
982 	if (len >= SMTP_LINE_MAX)
983 		return "line too long";
984 
985 	if (len > 3) {
986 		if (msg)
987 			*msg = line + 4;
988 		if (cont)
989 			*cont = (line[3] == '-');
990 	} else if (len == 3) {
991 		if (msg)
992 			*msg = line + 3;
993 		if (cont)
994 			*cont = 0;
995 	} else
996 		return "line too short";
997 
998 	/* validate reply code */
999 	if (line[0] < '2' || line[0] > '5' || !isdigit(line[1]) ||
1000 	    !isdigit(line[2]))
1001 		return "reply code out of range";
1002 
1003 	/* validate reply message */
1004 	for (i = 0; i < len; i++)
1005 		if (!isprint(line[i]))
1006 			return "non-printable character in reply";
1007 
1008 	return NULL;
1009 }
1010