xref: /illumos-gate/usr/src/common/smbsrv/smb_match.c (revision c10c16de)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #ifndef _KERNEL
26 #include <stdlib.h>
27 #include <string.h>
28 #else
29 #include <sys/types.h>
30 #include <sys/sunddi.h>
31 #endif
32 #include <smbsrv/string.h>
33 #include <smbsrv/smb.h>
34 
35 /*
36  * Maximum recursion depth for the wildcard match functions.
37  * These functions may recurse when processing a '*'.
38  */
39 #define	SMB_MATCH_DEPTH_MAX	32
40 
41 #define	SMB_CRC_POLYNOMIAL	0xD8B5D8B5
42 
43 static int smb_match_private(const char *, const char *, int *);
44 static int smb_match_ci_private(const char *, const char *, int *);
45 
46 /*
47  * smb_match
48  */
49 boolean_t
50 smb_match(char *patn, char *str)
51 {
52 	int depth = 0;
53 
54 	return (smb_match_private(patn, str, &depth) == 1);
55 }
56 
57 /*
58  * The '*' character matches multiple characters.
59  * The '?' character matches a single character.
60  *
61  * If the pattern has trailing '?'s then it matches the specified number
62  * of characters or less.  For example, "x??" matches "xab", "xa" and "x",
63  * but not "xabc".
64  *
65  * Returns:
66  * 1	match
67  * 0	no-match
68  * -1	no-match, too many wildcards in pattern
69  */
70 static int
71 smb_match_private(const char *patn, const char *str, int *depth)
72 {
73 	int rc;
74 
75 	for (;;) {
76 		switch (*patn) {
77 		case '\0':
78 			return (*str == '\0');
79 
80 		case '?':
81 			if (*str != 0) {
82 				str++;
83 				patn++;
84 				continue;
85 			} else {
86 				return (0);
87 			}
88 			/*NOTREACHED*/
89 
90 		case '*':
91 			patn += strspn(patn, "*");
92 			if (*patn == '\0')
93 				return (1);
94 
95 			if ((*depth)++ >= SMB_MATCH_DEPTH_MAX)
96 				return (-1);
97 
98 			while (*str) {
99 				rc = smb_match_private(patn, str, depth);
100 				if (rc != 0)
101 					return (rc);
102 				str++;
103 			}
104 			return (0);
105 
106 		default:
107 			if (*str != *patn)
108 				return (0);
109 			str++;
110 			patn++;
111 			continue;
112 		}
113 	}
114 	/*NOTREACHED*/
115 }
116 
117 /*
118  * smb_match_ci
119  */
120 boolean_t
121 smb_match_ci(char *patn, char *str)
122 {
123 	int depth = 0;
124 
125 	return (smb_match_ci_private(patn, str, &depth) == 1);
126 }
127 
128 /*
129  * The '*' character matches multiple characters.
130  * The '?' character matches a single character.
131  *
132  * If the pattern has trailing '?'s then it matches the specified number
133  * of characters or less.  For example, "x??" matches "xab", "xa" and "x",
134  * but not "xabc".
135  *
136  * Returns:
137  * 1	match
138  * 0	no-match
139  * -1	no-match, too many wildcards in pattern
140  */
141 static int
142 smb_match_ci_private(const char *patn, const char *str, int *depth)
143 {
144 	const char	*p;
145 	smb_wchar_t	wc1, wc2;
146 	int		nbytes1, nbytes2;
147 	int		rc;
148 
149 	/*
150 	 * "<" is a special pattern that matches only those names that do
151 	 * NOT have an extension. "." and ".." are ok.
152 	 */
153 	if (strcmp(patn, "<") == 0) {
154 		if ((strcmp(str, ".") == 0) || (strcmp(str, "..") == 0))
155 			return (1);
156 		if (strchr(str, '.') == 0)
157 			return (1);
158 		return (0);
159 	}
160 
161 	for (;;) {
162 		switch (*patn) {
163 		case '\0':
164 			return (*str == '\0');
165 
166 		case '?':
167 			if (*str != 0) {
168 				str++;
169 				patn++;
170 				continue;
171 			} else {
172 				p = patn;
173 				p += strspn(p, "?");
174 				return ((*p == '\0') ? 1 : 0);
175 			}
176 			/*NOTREACHED*/
177 
178 		case '*':
179 			patn += strspn(patn, "*");
180 			if (*patn == '\0')
181 				return (1);
182 
183 			if ((*depth)++ >= SMB_MATCH_DEPTH_MAX)
184 				return (-1);
185 
186 			while (*str) {
187 				rc = smb_match_ci_private(patn, str, depth);
188 				if (rc != 0)
189 					return (rc);
190 				str++;
191 			}
192 			return (0);
193 
194 		default:
195 			nbytes1 = smb_mbtowc(&wc1, patn, MTS_MB_CHAR_MAX);
196 			nbytes2 = smb_mbtowc(&wc2, str, MTS_MB_CHAR_MAX);
197 			if ((nbytes1 == -1) || (nbytes2 == -1))
198 				return (-1);
199 
200 			if (wc1 != wc2) {
201 				wc1 = smb_tolower(wc1);
202 				wc2 = smb_tolower(wc2);
203 				if (wc1 != wc2)
204 					return (0);
205 			}
206 
207 			patn += nbytes1;
208 			str += nbytes2;
209 			continue;
210 		}
211 	}
212 	/*NOTREACHED*/
213 }
214 
215 uint32_t
216 smb_crc_gen(uint8_t *buf, size_t len)
217 {
218 	uint32_t crc = SMB_CRC_POLYNOMIAL;
219 	uint8_t *p;
220 	int i;
221 
222 	for (p = buf, i = 0; i < len; ++i, ++p) {
223 		crc = (crc ^ (uint32_t)*p) + (crc << 12);
224 
225 		if (crc == 0 || crc == 0xFFFFFFFF)
226 			crc = SMB_CRC_POLYNOMIAL;
227 	}
228 
229 	return (crc);
230 }
231