xref: /freebsd/crypto/openssh/match.c (revision 535af610)
1535af610SEd Maste /* $OpenBSD: match.c,v 1.44 2023/04/06 03:19:32 djm Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray  *                    All rights reserved
6511b41d2SMark Murray  * Simple pattern matching, with '*' and '?' as wildcards.
7511b41d2SMark Murray  *
8b66f2d16SKris Kennaway  * As far as I am concerned, the code I have written for this software
9b66f2d16SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
10b66f2d16SKris Kennaway  * software must be clearly marked as such, and if the derived work is
11b66f2d16SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
12b66f2d16SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
13511b41d2SMark Murray  */
141e8db6e2SBrian Feldman /*
151e8db6e2SBrian Feldman  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
161e8db6e2SBrian Feldman  *
171e8db6e2SBrian Feldman  * Redistribution and use in source and binary forms, with or without
181e8db6e2SBrian Feldman  * modification, are permitted provided that the following conditions
191e8db6e2SBrian Feldman  * are met:
201e8db6e2SBrian Feldman  * 1. Redistributions of source code must retain the above copyright
211e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer.
221e8db6e2SBrian Feldman  * 2. Redistributions in binary form must reproduce the above copyright
231e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer in the
241e8db6e2SBrian Feldman  *    documentation and/or other materials provided with the distribution.
251e8db6e2SBrian Feldman  *
261e8db6e2SBrian Feldman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
271e8db6e2SBrian Feldman  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
281e8db6e2SBrian Feldman  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
291e8db6e2SBrian Feldman  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
301e8db6e2SBrian Feldman  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
311e8db6e2SBrian Feldman  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
321e8db6e2SBrian Feldman  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
331e8db6e2SBrian Feldman  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
341e8db6e2SBrian Feldman  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
351e8db6e2SBrian Feldman  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
361e8db6e2SBrian Feldman  */
37511b41d2SMark Murray 
38511b41d2SMark Murray #include "includes.h"
39511b41d2SMark Murray 
40761efaa7SDag-Erling Smørgrav #include <sys/types.h>
41761efaa7SDag-Erling Smørgrav 
42761efaa7SDag-Erling Smørgrav #include <ctype.h>
43e4a9863fSDag-Erling Smørgrav #include <stdlib.h>
44761efaa7SDag-Erling Smørgrav #include <string.h>
4519261079SEd Maste #include <stdarg.h>
46d93a896eSDag-Erling Smørgrav #include <stdio.h>
47761efaa7SDag-Erling Smørgrav 
481e8db6e2SBrian Feldman #include "xmalloc.h"
49761efaa7SDag-Erling Smørgrav #include "match.h"
50d93a896eSDag-Erling Smørgrav #include "misc.h"
51511b41d2SMark Murray 
52511b41d2SMark Murray /*
53511b41d2SMark Murray  * Returns true if the given string matches the pattern (which may contain ?
54511b41d2SMark Murray  * and * as wildcards), and zero if it does not match.
55511b41d2SMark Murray  */
56511b41d2SMark Murray int
match_pattern(const char * s,const char * pattern)57511b41d2SMark Murray match_pattern(const char *s, const char *pattern)
58511b41d2SMark Murray {
59511b41d2SMark Murray 	for (;;) {
60511b41d2SMark Murray 		/* If at end of pattern, accept if also at end of string. */
61511b41d2SMark Murray 		if (!*pattern)
62511b41d2SMark Murray 			return !*s;
63511b41d2SMark Murray 
64511b41d2SMark Murray 		if (*pattern == '*') {
6519261079SEd Maste 			/* Skip this and any consecutive asterisks. */
6619261079SEd Maste 			while (*pattern == '*')
67511b41d2SMark Murray 				pattern++;
68511b41d2SMark Murray 
69511b41d2SMark Murray 			/* If at end of pattern, accept immediately. */
70511b41d2SMark Murray 			if (!*pattern)
71511b41d2SMark Murray 				return 1;
72511b41d2SMark Murray 
73511b41d2SMark Murray 			/* If next character in pattern is known, optimize. */
74511b41d2SMark Murray 			if (*pattern != '?' && *pattern != '*') {
75511b41d2SMark Murray 				/*
76511b41d2SMark Murray 				 * Look instances of the next character in
77511b41d2SMark Murray 				 * pattern, and try to match starting from
78511b41d2SMark Murray 				 * those.
79511b41d2SMark Murray 				 */
80511b41d2SMark Murray 				for (; *s; s++)
81511b41d2SMark Murray 					if (*s == *pattern &&
82511b41d2SMark Murray 					    match_pattern(s + 1, pattern + 1))
83511b41d2SMark Murray 						return 1;
84511b41d2SMark Murray 				/* Failed. */
85511b41d2SMark Murray 				return 0;
86511b41d2SMark Murray 			}
87511b41d2SMark Murray 			/*
88511b41d2SMark Murray 			 * Move ahead one character at a time and try to
89511b41d2SMark Murray 			 * match at each position.
90511b41d2SMark Murray 			 */
91511b41d2SMark Murray 			for (; *s; s++)
92511b41d2SMark Murray 				if (match_pattern(s, pattern))
93511b41d2SMark Murray 					return 1;
94511b41d2SMark Murray 			/* Failed. */
95511b41d2SMark Murray 			return 0;
96511b41d2SMark Murray 		}
97511b41d2SMark Murray 		/*
98511b41d2SMark Murray 		 * There must be at least one more character in the string.
99511b41d2SMark Murray 		 * If we are at the end, fail.
100511b41d2SMark Murray 		 */
101511b41d2SMark Murray 		if (!*s)
102511b41d2SMark Murray 			return 0;
103511b41d2SMark Murray 
104511b41d2SMark Murray 		/* Check if the next character of the string is acceptable. */
105511b41d2SMark Murray 		if (*pattern != '?' && *pattern != *s)
106511b41d2SMark Murray 			return 0;
107511b41d2SMark Murray 
108511b41d2SMark Murray 		/* Move to the next character, both in string and in pattern. */
109511b41d2SMark Murray 		s++;
110511b41d2SMark Murray 		pattern++;
111511b41d2SMark Murray 	}
112511b41d2SMark Murray 	/* NOTREACHED */
113511b41d2SMark Murray }
114a8f6863aSKris Kennaway 
115a8f6863aSKris Kennaway /*
116ae1f160dSDag-Erling Smørgrav  * Tries to match the string against the
117a8f6863aSKris Kennaway  * comma-separated sequence of subpatterns (each possibly preceded by ! to
118b66f2d16SKris Kennaway  * indicate negation).  Returns -1 if negation matches, 1 if there is
119b66f2d16SKris Kennaway  * a positive match, 0 if there is no match at all.
120a8f6863aSKris Kennaway  */
121a8f6863aSKris Kennaway int
match_pattern_list(const char * string,const char * pattern,int dolower)122557f75e5SDag-Erling Smørgrav match_pattern_list(const char *string, const char *pattern, int dolower)
123a8f6863aSKris Kennaway {
124a8f6863aSKris Kennaway 	char sub[1024];
125a8f6863aSKris Kennaway 	int negated;
126a8f6863aSKris Kennaway 	int got_positive;
127557f75e5SDag-Erling Smørgrav 	u_int i, subi, len = strlen(pattern);
128a8f6863aSKris Kennaway 
129a8f6863aSKris Kennaway 	got_positive = 0;
130a8f6863aSKris Kennaway 	for (i = 0; i < len;) {
131a8f6863aSKris Kennaway 		/* Check if the subpattern is negated. */
132a8f6863aSKris Kennaway 		if (pattern[i] == '!') {
133a8f6863aSKris Kennaway 			negated = 1;
134a8f6863aSKris Kennaway 			i++;
135a8f6863aSKris Kennaway 		} else
136a8f6863aSKris Kennaway 			negated = 0;
137a8f6863aSKris Kennaway 
138a8f6863aSKris Kennaway 		/*
139a8f6863aSKris Kennaway 		 * Extract the subpattern up to a comma or end.  Convert the
140a8f6863aSKris Kennaway 		 * subpattern to lowercase.
141a8f6863aSKris Kennaway 		 */
142a8f6863aSKris Kennaway 		for (subi = 0;
143a8f6863aSKris Kennaway 		    i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
144a8f6863aSKris Kennaway 		    subi++, i++)
145f7167e0eSDag-Erling Smørgrav 			sub[subi] = dolower && isupper((u_char)pattern[i]) ?
146f7167e0eSDag-Erling Smørgrav 			    tolower((u_char)pattern[i]) : pattern[i];
147a8f6863aSKris Kennaway 		/* If subpattern too long, return failure (no match). */
148a8f6863aSKris Kennaway 		if (subi >= sizeof(sub) - 1)
149a8f6863aSKris Kennaway 			return 0;
150a8f6863aSKris Kennaway 
151d93a896eSDag-Erling Smørgrav 		/* If the subpattern was terminated by a comma, then skip it. */
152a8f6863aSKris Kennaway 		if (i < len && pattern[i] == ',')
153a8f6863aSKris Kennaway 			i++;
154a8f6863aSKris Kennaway 
155a8f6863aSKris Kennaway 		/* Null-terminate the subpattern. */
156a8f6863aSKris Kennaway 		sub[subi] = '\0';
157a8f6863aSKris Kennaway 
158ae1f160dSDag-Erling Smørgrav 		/* Try to match the subpattern against the string. */
159ae1f160dSDag-Erling Smørgrav 		if (match_pattern(string, sub)) {
160a8f6863aSKris Kennaway 			if (negated)
161b66f2d16SKris Kennaway 				return -1;		/* Negative */
162a8f6863aSKris Kennaway 			else
163b66f2d16SKris Kennaway 				got_positive = 1;	/* Positive */
164a8f6863aSKris Kennaway 		}
165a8f6863aSKris Kennaway 	}
166a8f6863aSKris Kennaway 
167a8f6863aSKris Kennaway 	/*
168a8f6863aSKris Kennaway 	 * Return success if got a positive match.  If there was a negative
169b66f2d16SKris Kennaway 	 * match, we have already returned -1 and never get here.
170a8f6863aSKris Kennaway 	 */
171a8f6863aSKris Kennaway 	return got_positive;
172a8f6863aSKris Kennaway }
1731e8db6e2SBrian Feldman 
17419261079SEd Maste /* Match a list representing users or groups. */
17519261079SEd Maste int
match_usergroup_pattern_list(const char * string,const char * pattern)17619261079SEd Maste match_usergroup_pattern_list(const char *string, const char *pattern)
17719261079SEd Maste {
17819261079SEd Maste #ifdef HAVE_CYGWIN
17919261079SEd Maste 	/* Windows usernames may be Unicode and are not case sensitive */
18019261079SEd Maste 	return cygwin_ug_match_pattern_list(string, pattern);
18119261079SEd Maste #else
18219261079SEd Maste 	/* Case sensitive match */
18319261079SEd Maste 	return match_pattern_list(string, pattern, 0);
18419261079SEd Maste #endif
18519261079SEd Maste }
18619261079SEd Maste 
187ae1f160dSDag-Erling Smørgrav /*
188ae1f160dSDag-Erling Smørgrav  * Tries to match the host name (which must be in all lowercase) against the
189ae1f160dSDag-Erling Smørgrav  * comma-separated sequence of subpatterns (each possibly preceded by ! to
190ae1f160dSDag-Erling Smørgrav  * indicate negation).  Returns -1 if negation matches, 1 if there is
191ae1f160dSDag-Erling Smørgrav  * a positive match, 0 if there is no match at all.
192ae1f160dSDag-Erling Smørgrav  */
193ae1f160dSDag-Erling Smørgrav int
match_hostname(const char * host,const char * pattern)194557f75e5SDag-Erling Smørgrav match_hostname(const char *host, const char *pattern)
195ae1f160dSDag-Erling Smørgrav {
196d93a896eSDag-Erling Smørgrav 	char *hostcopy = xstrdup(host);
197d93a896eSDag-Erling Smørgrav 	int r;
198d93a896eSDag-Erling Smørgrav 
199d93a896eSDag-Erling Smørgrav 	lowercase(hostcopy);
200d93a896eSDag-Erling Smørgrav 	r = match_pattern_list(hostcopy, pattern, 1);
201d93a896eSDag-Erling Smørgrav 	free(hostcopy);
202d93a896eSDag-Erling Smørgrav 	return r;
203ae1f160dSDag-Erling Smørgrav }
2041e8db6e2SBrian Feldman 
205ae1f160dSDag-Erling Smørgrav /*
206ae1f160dSDag-Erling Smørgrav  * returns 0 if we get a negative match for the hostname or the ip
207d4af9e69SDag-Erling Smørgrav  * or if we get no match at all.  returns -1 on error, or 1 on
208d4af9e69SDag-Erling Smørgrav  * successful match.
209ae1f160dSDag-Erling Smørgrav  */
210ae1f160dSDag-Erling Smørgrav int
match_host_and_ip(const char * host,const char * ipaddr,const char * patterns)211ae1f160dSDag-Erling Smørgrav match_host_and_ip(const char *host, const char *ipaddr,
212ae1f160dSDag-Erling Smørgrav     const char *patterns)
213ae1f160dSDag-Erling Smørgrav {
214ae1f160dSDag-Erling Smørgrav 	int mhost, mip;
215ae1f160dSDag-Erling Smørgrav 
216d4af9e69SDag-Erling Smørgrav 	if ((mip = addr_match_list(ipaddr, patterns)) == -2)
217ca86bcf2SDag-Erling Smørgrav 		return -1; /* error in ipaddr match */
218ca86bcf2SDag-Erling Smørgrav 	else if (host == NULL || ipaddr == NULL || mip == -1)
219ca86bcf2SDag-Erling Smørgrav 		return 0; /* negative ip address match, or testing pattern */
220d4af9e69SDag-Erling Smørgrav 
221ae1f160dSDag-Erling Smørgrav 	/* negative hostname match */
222557f75e5SDag-Erling Smørgrav 	if ((mhost = match_hostname(host, patterns)) == -1)
223ae1f160dSDag-Erling Smørgrav 		return 0;
224ae1f160dSDag-Erling Smørgrav 	/* no match at all */
225ae1f160dSDag-Erling Smørgrav 	if (mhost == 0 && mip == 0)
226ae1f160dSDag-Erling Smørgrav 		return 0;
227ae1f160dSDag-Erling Smørgrav 	return 1;
228ae1f160dSDag-Erling Smørgrav }
229ae1f160dSDag-Erling Smørgrav 
230ae1f160dSDag-Erling Smørgrav /*
231ca86bcf2SDag-Erling Smørgrav  * Match user, user@host_or_ip, user@host_or_ip_list against pattern.
232ca86bcf2SDag-Erling Smørgrav  * If user, host and ipaddr are all NULL then validate pattern/
233ca86bcf2SDag-Erling Smørgrav  * Returns -1 on invalid pattern, 0 on no match, 1 on match.
234ae1f160dSDag-Erling Smørgrav  */
235ae1f160dSDag-Erling Smørgrav int
match_user(const char * user,const char * host,const char * ipaddr,const char * pattern)236ae1f160dSDag-Erling Smørgrav match_user(const char *user, const char *host, const char *ipaddr,
237ae1f160dSDag-Erling Smørgrav     const char *pattern)
238ae1f160dSDag-Erling Smørgrav {
239ae1f160dSDag-Erling Smørgrav 	char *p, *pat;
240ae1f160dSDag-Erling Smørgrav 	int ret;
241ae1f160dSDag-Erling Smørgrav 
242ca86bcf2SDag-Erling Smørgrav 	/* test mode */
243ca86bcf2SDag-Erling Smørgrav 	if (user == NULL && host == NULL && ipaddr == NULL) {
244ca86bcf2SDag-Erling Smørgrav 		if ((p = strchr(pattern, '@')) != NULL &&
245ca86bcf2SDag-Erling Smørgrav 		    match_host_and_ip(NULL, NULL, p + 1) < 0)
246ca86bcf2SDag-Erling Smørgrav 			return -1;
247ca86bcf2SDag-Erling Smørgrav 		return 0;
248ca86bcf2SDag-Erling Smørgrav 	}
249ca86bcf2SDag-Erling Smørgrav 
250535af610SEd Maste 	if (user == NULL)
251535af610SEd Maste 		return 0; /* shouldn't happen */
252535af610SEd Maste 
253ae1f160dSDag-Erling Smørgrav 	if ((p = strchr(pattern, '@')) == NULL)
254ae1f160dSDag-Erling Smørgrav 		return match_pattern(user, pattern);
255ae1f160dSDag-Erling Smørgrav 
256ae1f160dSDag-Erling Smørgrav 	pat = xstrdup(pattern);
257ae1f160dSDag-Erling Smørgrav 	p = strchr(pat, '@');
258ae1f160dSDag-Erling Smørgrav 	*p++ = '\0';
259ae1f160dSDag-Erling Smørgrav 
260ae1f160dSDag-Erling Smørgrav 	if ((ret = match_pattern(user, pat)) == 1)
261ae1f160dSDag-Erling Smørgrav 		ret = match_host_and_ip(host, ipaddr, p);
262e4a9863fSDag-Erling Smørgrav 	free(pat);
263ae1f160dSDag-Erling Smørgrav 
264ae1f160dSDag-Erling Smørgrav 	return ret;
265ae1f160dSDag-Erling Smørgrav }
266ae1f160dSDag-Erling Smørgrav 
267ae1f160dSDag-Erling Smørgrav /*
268ae1f160dSDag-Erling Smørgrav  * Returns first item from client-list that is also supported by server-list,
269e4a9863fSDag-Erling Smørgrav  * caller must free the returned string.
270ae1f160dSDag-Erling Smørgrav  */
271ae1f160dSDag-Erling Smørgrav #define	MAX_PROP	40
2721e8db6e2SBrian Feldman #define	SEP	","
2731e8db6e2SBrian Feldman char *
match_list(const char * client,const char * server,u_int * next)2741e8db6e2SBrian Feldman match_list(const char *client, const char *server, u_int *next)
2751e8db6e2SBrian Feldman {
2761e8db6e2SBrian Feldman 	char *sproposals[MAX_PROP];
2771e8db6e2SBrian Feldman 	char *c, *s, *p, *ret, *cp, *sp;
2781e8db6e2SBrian Feldman 	int i, j, nproposals;
2791e8db6e2SBrian Feldman 
2801e8db6e2SBrian Feldman 	c = cp = xstrdup(client);
2811e8db6e2SBrian Feldman 	s = sp = xstrdup(server);
2821e8db6e2SBrian Feldman 
2831e8db6e2SBrian Feldman 	for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
2841e8db6e2SBrian Feldman 	    (p = strsep(&sp, SEP)), i++) {
2851e8db6e2SBrian Feldman 		if (i < MAX_PROP)
2861e8db6e2SBrian Feldman 			sproposals[i] = p;
2871e8db6e2SBrian Feldman 		else
2881e8db6e2SBrian Feldman 			break;
2891e8db6e2SBrian Feldman 	}
2901e8db6e2SBrian Feldman 	nproposals = i;
2911e8db6e2SBrian Feldman 
2921e8db6e2SBrian Feldman 	for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
2931e8db6e2SBrian Feldman 	    (p = strsep(&cp, SEP)), i++) {
2941e8db6e2SBrian Feldman 		for (j = 0; j < nproposals; j++) {
2951e8db6e2SBrian Feldman 			if (strcmp(p, sproposals[j]) == 0) {
2961e8db6e2SBrian Feldman 				ret = xstrdup(p);
2971e8db6e2SBrian Feldman 				if (next != NULL)
2981e8db6e2SBrian Feldman 					*next = (cp == NULL) ?
299043840dfSDag-Erling Smørgrav 					    strlen(c) : (u_int)(cp - c);
300e4a9863fSDag-Erling Smørgrav 				free(c);
301e4a9863fSDag-Erling Smørgrav 				free(s);
3021e8db6e2SBrian Feldman 				return ret;
3031e8db6e2SBrian Feldman 			}
3041e8db6e2SBrian Feldman 		}
3051e8db6e2SBrian Feldman 	}
3061e8db6e2SBrian Feldman 	if (next != NULL)
3071e8db6e2SBrian Feldman 		*next = strlen(c);
308e4a9863fSDag-Erling Smørgrav 	free(c);
309e4a9863fSDag-Erling Smørgrav 	free(s);
3101e8db6e2SBrian Feldman 	return NULL;
3111e8db6e2SBrian Feldman }
312d93a896eSDag-Erling Smørgrav 
313d93a896eSDag-Erling Smørgrav /*
314190cef3dSDag-Erling Smørgrav  * Filter proposal using pattern-list filter.
31519261079SEd Maste  * "denylist" determines sense of filter:
316190cef3dSDag-Erling Smørgrav  * non-zero indicates that items matching filter should be excluded.
317190cef3dSDag-Erling Smørgrav  * zero indicates that only items matching filter should be included.
318190cef3dSDag-Erling Smørgrav  * returns NULL on allocation error, otherwise caller must free result.
319d93a896eSDag-Erling Smørgrav  */
320190cef3dSDag-Erling Smørgrav static char *
filter_list(const char * proposal,const char * filter,int denylist)32119261079SEd Maste filter_list(const char *proposal, const char *filter, int denylist)
322d93a896eSDag-Erling Smørgrav {
323d93a896eSDag-Erling Smørgrav 	size_t len = strlen(proposal) + 1;
324d93a896eSDag-Erling Smørgrav 	char *fix_prop = malloc(len);
325d93a896eSDag-Erling Smørgrav 	char *orig_prop = strdup(proposal);
326d93a896eSDag-Erling Smørgrav 	char *cp, *tmp;
327190cef3dSDag-Erling Smørgrav 	int r;
328d93a896eSDag-Erling Smørgrav 
329d93a896eSDag-Erling Smørgrav 	if (fix_prop == NULL || orig_prop == NULL) {
330d93a896eSDag-Erling Smørgrav 		free(orig_prop);
331d93a896eSDag-Erling Smørgrav 		free(fix_prop);
332d93a896eSDag-Erling Smørgrav 		return NULL;
333d93a896eSDag-Erling Smørgrav 	}
334d93a896eSDag-Erling Smørgrav 
335d93a896eSDag-Erling Smørgrav 	tmp = orig_prop;
336d93a896eSDag-Erling Smørgrav 	*fix_prop = '\0';
337d93a896eSDag-Erling Smørgrav 	while ((cp = strsep(&tmp, ",")) != NULL) {
338190cef3dSDag-Erling Smørgrav 		r = match_pattern_list(cp, filter, 0);
33919261079SEd Maste 		if ((denylist && r != 1) || (!denylist && r == 1)) {
340d93a896eSDag-Erling Smørgrav 			if (*fix_prop != '\0')
341d93a896eSDag-Erling Smørgrav 				strlcat(fix_prop, ",", len);
342d93a896eSDag-Erling Smørgrav 			strlcat(fix_prop, cp, len);
343d93a896eSDag-Erling Smørgrav 		}
344d93a896eSDag-Erling Smørgrav 	}
345d93a896eSDag-Erling Smørgrav 	free(orig_prop);
346d93a896eSDag-Erling Smørgrav 	return fix_prop;
347d93a896eSDag-Erling Smørgrav }
348d93a896eSDag-Erling Smørgrav 
349190cef3dSDag-Erling Smørgrav /*
350190cef3dSDag-Erling Smørgrav  * Filters a comma-separated list of strings, excluding any entry matching
351190cef3dSDag-Erling Smørgrav  * the 'filter' pattern list. Caller must free returned string.
352190cef3dSDag-Erling Smørgrav  */
353190cef3dSDag-Erling Smørgrav char *
match_filter_denylist(const char * proposal,const char * filter)35419261079SEd Maste match_filter_denylist(const char *proposal, const char *filter)
355190cef3dSDag-Erling Smørgrav {
356190cef3dSDag-Erling Smørgrav 	return filter_list(proposal, filter, 1);
357190cef3dSDag-Erling Smørgrav }
358190cef3dSDag-Erling Smørgrav 
359190cef3dSDag-Erling Smørgrav /*
360190cef3dSDag-Erling Smørgrav  * Filters a comma-separated list of strings, including only entries matching
361190cef3dSDag-Erling Smørgrav  * the 'filter' pattern list. Caller must free returned string.
362190cef3dSDag-Erling Smørgrav  */
363190cef3dSDag-Erling Smørgrav char *
match_filter_allowlist(const char * proposal,const char * filter)36419261079SEd Maste match_filter_allowlist(const char *proposal, const char *filter)
365190cef3dSDag-Erling Smørgrav {
366190cef3dSDag-Erling Smørgrav 	return filter_list(proposal, filter, 0);
367190cef3dSDag-Erling Smørgrav }
368