xref: /openbsd/usr.sbin/smtpd/parser.c (revision d3140113)
1*d3140113Seric /*	$OpenBSD: parser.c,v 1.43 2021/06/14 17:58:15 eric Exp $	*/
2c4f9d530Sgilles 
3c4f9d530Sgilles /*
47a7bc169Seric  * Copyright (c) 2013 Eric Faurot	<eric@openbsd.org>
5c4f9d530Sgilles  *
6c4f9d530Sgilles  * Permission to use, copy, modify, and distribute this software for any
7c4f9d530Sgilles  * purpose with or without fee is hereby granted, provided that the above
8c4f9d530Sgilles  * copyright notice and this permission notice appear in all copies.
9c4f9d530Sgilles  *
10c4f9d530Sgilles  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11c4f9d530Sgilles  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12c4f9d530Sgilles  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13c4f9d530Sgilles  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14c4f9d530Sgilles  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15c4f9d530Sgilles  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16c4f9d530Sgilles  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17c4f9d530Sgilles  */
18c4f9d530Sgilles 
19c4f9d530Sgilles #include <sys/queue.h>
205b6a9ce9Seric #include <sys/socket.h>
215b6a9ce9Seric 
225b6a9ce9Seric #include <netinet/in.h>
235b6a9ce9Seric #include <net/if.h>
24c4f9d530Sgilles 
25*d3140113Seric #include <arpa/inet.h>
267a7bc169Seric #include <err.h>
277a7bc169Seric #include <inttypes.h>
287a7bc169Seric #include <limits.h>
295b6a9ce9Seric #include <netdb.h>
307a7bc169Seric #include <stdio.h>
317a7bc169Seric #include <stdlib.h>
327a7bc169Seric #include <string.h>
33c4f9d530Sgilles 
34c4f9d530Sgilles #include "parser.h"
35c4f9d530Sgilles 
367a7bc169Seric uint64_t text_to_evpid(const char *);
377a7bc169Seric uint32_t text_to_msgid(const char *);
387a7bc169Seric 
397a7bc169Seric struct node {
407a7bc169Seric 	int			 type;
417a7bc169Seric 	const char		*token;
427a7bc169Seric 	struct node		*parent;
437a7bc169Seric 	TAILQ_ENTRY(node)	 entry;
447a7bc169Seric 	TAILQ_HEAD(, node)	 children;
457a7bc169Seric 	int			(*cmd)(int, struct parameter*);
46c4f9d530Sgilles };
47c4f9d530Sgilles 
487a7bc169Seric static struct node	*root;
49c4f9d530Sgilles 
505b6a9ce9Seric static int text_to_sockaddr(struct sockaddr *, int, const char *);
515b6a9ce9Seric 
527a7bc169Seric #define ARGVMAX	64
53c4f9d530Sgilles 
547a7bc169Seric int
cmd_install(const char * pattern,int (* cmd)(int,struct parameter *))557a7bc169Seric cmd_install(const char *pattern, int (*cmd)(int, struct parameter*))
56c4f9d530Sgilles {
577a7bc169Seric 	struct node	*node, *tmp;
587a7bc169Seric 	char		*s, *str, *argv[ARGVMAX], **ap;
597a7bc169Seric 	int		 i, n;
60c4f9d530Sgilles 
617a7bc169Seric 	/* Tokenize */
627a7bc169Seric 	str = s = strdup(pattern);
637a7bc169Seric 	if (str == NULL)
647a7bc169Seric 		err(1, "strdup");
657a7bc169Seric 	n = 0;
667a7bc169Seric 	for (ap = argv; n < ARGVMAX && (*ap = strsep(&str, " \t")) != NULL;) {
677a7bc169Seric 		if (**ap != '\0') {
687a7bc169Seric 			ap++;
697a7bc169Seric 			n++;
703d46f2feSgilles 		}
713d46f2feSgilles 	}
727a7bc169Seric 	*ap = NULL;
737a7bc169Seric 
747a7bc169Seric 	if (root == NULL) {
757a7bc169Seric 		root = calloc(1, sizeof (*root));
767a7bc169Seric 		TAILQ_INIT(&root->children);
777a7bc169Seric 	}
787a7bc169Seric 	node = root;
797a7bc169Seric 
807a7bc169Seric 	for (i = 0; i < n; i++) {
817a7bc169Seric 		TAILQ_FOREACH(tmp, &node->children, entry) {
827a7bc169Seric 			if (!strcmp(tmp->token, argv[i])) {
837a7bc169Seric 				node = tmp;
84c4f9d530Sgilles 				break;
85c4f9d530Sgilles 			}
86c4f9d530Sgilles 		}
877a7bc169Seric 		if (tmp == NULL) {
887a7bc169Seric 			tmp = calloc(1, sizeof (*tmp));
897a7bc169Seric 			TAILQ_INIT(&tmp->children);
907a7bc169Seric 			if (!strcmp(argv[i], "<str>"))
917a7bc169Seric 				tmp->type = P_STR;
927a7bc169Seric 			else if (!strcmp(argv[i], "<int>"))
937a7bc169Seric 				tmp->type = P_INT;
947a7bc169Seric 			else if (!strcmp(argv[i], "<msgid>"))
957a7bc169Seric 				tmp->type = P_MSGID;
967a7bc169Seric 			else if (!strcmp(argv[i], "<evpid>"))
977a7bc169Seric 				tmp->type = P_EVPID;
987a7bc169Seric 			else if (!strcmp(argv[i], "<routeid>"))
997a7bc169Seric 				tmp->type = P_ROUTEID;
1005b6a9ce9Seric 			else if (!strcmp(argv[i], "<addr>"))
1015b6a9ce9Seric 				tmp->type = P_ADDR;
1027a7bc169Seric 			else
1037a7bc169Seric 				tmp->type = P_TOKEN;
1047a7bc169Seric 			tmp->token = strdup(argv[i]);
1057a7bc169Seric 			tmp->parent = node;
1067a7bc169Seric 			TAILQ_INSERT_TAIL(&node->children, tmp, entry);
1077a7bc169Seric 			node = tmp;
1087a7bc169Seric 		}
109c4f9d530Sgilles 	}
110c4f9d530Sgilles 
1117a7bc169Seric 	if (node->cmd)
1127a7bc169Seric 		errx(1, "duplicate pattern: %s", pattern);
1137a7bc169Seric 	node->cmd = cmd;
1147a7bc169Seric 
1157a7bc169Seric 	free(s);
1167a7bc169Seric 	return (n);
117c4f9d530Sgilles }
118c4f9d530Sgilles 
1197a7bc169Seric static int
cmd_check(const char * str,struct node * node,struct parameter * res)1207a7bc169Seric cmd_check(const char *str, struct node *node, struct parameter *res)
1217a7bc169Seric {
1227a7bc169Seric 	const char *e;
1237a7bc169Seric 
1247a7bc169Seric 	switch (node->type) {
1257a7bc169Seric 	case P_TOKEN:
1267a7bc169Seric 		if (!strcmp(str, node->token))
1277a7bc169Seric 			return (1);
1287a7bc169Seric 		return (0);
1297a7bc169Seric 
1307a7bc169Seric 	case P_STR:
1317a7bc169Seric 		res->u.u_str = str;
1327a7bc169Seric 		return (1);
1337a7bc169Seric 
1347a7bc169Seric 	case P_INT:
1357a7bc169Seric 		res->u.u_int = strtonum(str, INT_MIN, INT_MAX, &e);
1367a7bc169Seric 		if (e)
1377a7bc169Seric 			return (0);
1387a7bc169Seric 		return (1);
1397a7bc169Seric 
1407a7bc169Seric 	case P_MSGID:
1417a7bc169Seric 		if (strlen(str) != 8)
1427a7bc169Seric 			return (0);
1437a7bc169Seric 		res->u.u_msgid = text_to_msgid(str);
1447a7bc169Seric 		if (res->u.u_msgid == 0)
1457a7bc169Seric 			return (0);
1467a7bc169Seric 		return (1);
1477a7bc169Seric 
1487a7bc169Seric 	case P_EVPID:
1497a7bc169Seric 		if (strlen(str) != 16)
1507a7bc169Seric 			return (0);
1517a7bc169Seric 		res->u.u_evpid = text_to_evpid(str);
1527a7bc169Seric 		if (res->u.u_evpid == 0)
1537a7bc169Seric 			return (0);
1547a7bc169Seric 		return (1);
1557a7bc169Seric 
1567a7bc169Seric 	case P_ROUTEID:
15722cff71cSeric 		res->u.u_routeid = strtonum(str, 1, LLONG_MAX, &e);
1587a7bc169Seric 		if (e)
1597a7bc169Seric 			return (0);
1607a7bc169Seric 		return (1);
1617a7bc169Seric 
1625b6a9ce9Seric 	case P_ADDR:
1635b6a9ce9Seric 		if (text_to_sockaddr((struct sockaddr *)&res->u.u_ss, PF_UNSPEC, str) == 0)
1645b6a9ce9Seric 			return (1);
1655b6a9ce9Seric 		return (0);
1665b6a9ce9Seric 
1677a7bc169Seric 	default:
168d7bcae4dSeric 		errx(1, "bad token type: %d", node->type);
1697a7bc169Seric 		return (0);
1707a7bc169Seric 	}
1717a7bc169Seric }
1727a7bc169Seric 
1737a7bc169Seric int
cmd_run(int argc,char ** argv)1747a7bc169Seric cmd_run(int argc, char **argv)
1757a7bc169Seric {
1767a7bc169Seric 	struct parameter param[ARGVMAX];
1777a7bc169Seric 	struct node	*node, *tmp, *stack[ARGVMAX], *best;
1787a7bc169Seric 	int		 i, j, np;
1797a7bc169Seric 
1807a7bc169Seric 	node = root;
1817a7bc169Seric 	np = 0;
1827a7bc169Seric 
1837a7bc169Seric 	for (i = 0; i < argc; i++) {
1847a7bc169Seric 		TAILQ_FOREACH(tmp, &node->children, entry) {
1857a7bc169Seric 			if (cmd_check(argv[i], tmp, &param[np])) {
1867a7bc169Seric 				stack[i] = tmp;
1877a7bc169Seric 				node = tmp;
1887a7bc169Seric 				param[np].type = node->type;
1897a7bc169Seric 				if (node->type != P_TOKEN)
1907a7bc169Seric 					np++;
1917a7bc169Seric 				break;
1927a7bc169Seric 			}
1937a7bc169Seric 		}
1947a7bc169Seric 		if (tmp == NULL) {
1957a7bc169Seric 			best = NULL;
1967a7bc169Seric 			TAILQ_FOREACH(tmp, &node->children, entry) {
1977a7bc169Seric 				if (tmp->type != P_TOKEN)
1987a7bc169Seric 					continue;
1997a7bc169Seric 				if (strstr(tmp->token, argv[i]) != tmp->token)
2007a7bc169Seric 					continue;
2017a7bc169Seric 				if (best)
2027a7bc169Seric 					goto fail;
2037a7bc169Seric 				best = tmp;
2047a7bc169Seric 			}
2057a7bc169Seric 			if (best == NULL)
2067a7bc169Seric 				goto fail;
2077a7bc169Seric 			stack[i] = best;
2087a7bc169Seric 			node = best;
2097a7bc169Seric 			param[np].type = node->type;
2107a7bc169Seric 			if (node->type != P_TOKEN)
2117a7bc169Seric 				np++;
2127a7bc169Seric 		}
2137a7bc169Seric 	}
2147a7bc169Seric 
2157a7bc169Seric 	if (node->cmd == NULL)
2167a7bc169Seric 		goto fail;
2177a7bc169Seric 
2180fcb81a3Seric 	return (node->cmd(np, np ? param : NULL));
2197a7bc169Seric 
2207a7bc169Seric fail:
22174c984d4Sgilles 	if (TAILQ_FIRST(&node->children) == NULL) {
22274c984d4Sgilles 		fprintf(stderr, "invalid command\n");
22374c984d4Sgilles 		return (-1);
22474c984d4Sgilles 	}
22574c984d4Sgilles 
2267a7bc169Seric 	fprintf(stderr, "possibilities are:\n");
2277a7bc169Seric 	TAILQ_FOREACH(tmp, &node->children, entry) {
2287a7bc169Seric 		for (j = 0; j < i; j++)
2297a7bc169Seric 			fprintf(stderr, "%s%s", j?" ":"", stack[j]->token);
2307a7bc169Seric 		fprintf(stderr, "%s%s\n", i?" ":"", tmp->token);
2317a7bc169Seric 	}
2327a7bc169Seric 
2337a7bc169Seric 	return (-1);
2347a7bc169Seric }
2357a7bc169Seric 
2367a7bc169Seric int
cmd_show_params(int argc,struct parameter * argv)2377a7bc169Seric cmd_show_params(int argc, struct parameter *argv)
238c4f9d530Sgilles {
239c4f9d530Sgilles 	int	i;
240c4f9d530Sgilles 
2417a7bc169Seric 	for (i = 0; i < argc; i++) {
2427a7bc169Seric 		switch(argv[i].type) {
2437a7bc169Seric 		case P_STR:
2447a7bc169Seric 			printf(" str:\"%s\"", argv[i].u.u_str);
245c4f9d530Sgilles 			break;
2467a7bc169Seric 		case P_INT:
247d7bcae4dSeric 			printf(" int:%d", argv[i].u.u_int);
248c4f9d530Sgilles 			break;
2497a7bc169Seric 		case P_MSGID:
2507a7bc169Seric 			printf(" msgid:%08"PRIx32, argv[i].u.u_msgid);
2513d46f2feSgilles 			break;
2527a7bc169Seric 		case P_EVPID:
2537a7bc169Seric 			printf(" evpid:%016"PRIx64, argv[i].u.u_evpid);
254c4f9d530Sgilles 			break;
2557a7bc169Seric 		case P_ROUTEID:
2567a7bc169Seric 			printf(" routeid:%016"PRIx64, argv[i].u.u_routeid);
2577a7bc169Seric 			break;
2587a7bc169Seric 		default:
259d7bcae4dSeric 			printf(" ???:%d", argv[i].type);
260c4f9d530Sgilles 		}
261c4f9d530Sgilles 	}
2627a7bc169Seric 	printf ("\n");
2637a7bc169Seric 	return (1);
264c4f9d530Sgilles }
2655b6a9ce9Seric 
2665b6a9ce9Seric static int
text_to_sockaddr(struct sockaddr * sa,int family,const char * str)2675b6a9ce9Seric text_to_sockaddr(struct sockaddr *sa, int family, const char *str)
2685b6a9ce9Seric {
2695b6a9ce9Seric 	struct in_addr		 ina;
2705b6a9ce9Seric 	struct in6_addr		 in6a;
271c09413deSgilles 	struct sockaddr_in	*in;
272c09413deSgilles 	struct sockaddr_in6	*in6;
2735b6a9ce9Seric 	char			*cp, *str2;
2745b6a9ce9Seric 	const char		*errstr;
2755b6a9ce9Seric 
2765b6a9ce9Seric 	switch (family) {
2775b6a9ce9Seric 	case PF_UNSPEC:
2785b6a9ce9Seric 		if (text_to_sockaddr(sa, PF_INET, str) == 0)
2795b6a9ce9Seric 			return (0);
2805b6a9ce9Seric 		return text_to_sockaddr(sa, PF_INET6, str);
2815b6a9ce9Seric 
2825b6a9ce9Seric 	case PF_INET:
2835b6a9ce9Seric 		if (inet_pton(PF_INET, str, &ina) != 1)
2845b6a9ce9Seric 			return (-1);
2855b6a9ce9Seric 
286c09413deSgilles 		in = (struct sockaddr_in *)sa;
287c09413deSgilles 		memset(in, 0, sizeof *in);
288c09413deSgilles 		in->sin_len = sizeof(struct sockaddr_in);
289c09413deSgilles 		in->sin_family = PF_INET;
290c09413deSgilles 		in->sin_addr.s_addr = ina.s_addr;
2915b6a9ce9Seric 		return (0);
2925b6a9ce9Seric 
2935b6a9ce9Seric 	case PF_INET6:
2945b6a9ce9Seric 		cp = strchr(str, SCOPE_DELIMITER);
2955b6a9ce9Seric 		if (cp) {
2965b6a9ce9Seric 			str2 = strdup(str);
2975b6a9ce9Seric 			if (str2 == NULL)
2985b6a9ce9Seric 				return (-1);
2995b6a9ce9Seric 			str2[cp - str] = '\0';
3005b6a9ce9Seric 			if (inet_pton(PF_INET6, str2, &in6a) != 1) {
3015b6a9ce9Seric 				free(str2);
3025b6a9ce9Seric 				return (-1);
3035b6a9ce9Seric 			}
3045b6a9ce9Seric 			cp++;
3055b6a9ce9Seric 			free(str2);
3065b6a9ce9Seric 		} else if (inet_pton(PF_INET6, str, &in6a) != 1)
3075b6a9ce9Seric 			return (-1);
3085b6a9ce9Seric 
309c09413deSgilles 		in6 = (struct sockaddr_in6 *)sa;
310c09413deSgilles 		memset(in6, 0, sizeof *in6);
311c09413deSgilles 		in6->sin6_len = sizeof(struct sockaddr_in6);
312c09413deSgilles 		in6->sin6_family = PF_INET6;
313c09413deSgilles 		in6->sin6_addr = in6a;
3145b6a9ce9Seric 
3155b6a9ce9Seric 		if (cp == NULL)
3165b6a9ce9Seric 			return (0);
3175b6a9ce9Seric 
3185b6a9ce9Seric 		if (IN6_IS_ADDR_LINKLOCAL(&in6a) ||
3195b6a9ce9Seric 		    IN6_IS_ADDR_MC_LINKLOCAL(&in6a) ||
3205b6a9ce9Seric 		    IN6_IS_ADDR_MC_INTFACELOCAL(&in6a))
321c09413deSgilles 			if ((in6->sin6_scope_id = if_nametoindex(cp)))
3225b6a9ce9Seric 				return (0);
3235b6a9ce9Seric 
324c09413deSgilles 		in6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr);
3255b6a9ce9Seric 		if (errstr)
3265b6a9ce9Seric 			return (-1);
3275b6a9ce9Seric 		return (0);
3285b6a9ce9Seric 
3295b6a9ce9Seric 	default:
3305b6a9ce9Seric 		break;
3315b6a9ce9Seric 	}
3325b6a9ce9Seric 
3335b6a9ce9Seric 	return (-1);
3345b6a9ce9Seric }
335