xref: /illumos-gate/usr/src/common/smbsrv/smb_match.c (revision 634e26ec)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #ifndef _KERNEL
27 #include <stdlib.h>
28 #include <string.h>
29 #else
30 #include <sys/types.h>
31 #include <sys/sunddi.h>
32 #endif
33 #include <smbsrv/string.h>
34 #include <smbsrv/smb.h>
35 
36 /*
37  * Maximum recursion depth for the wildcard match functions.
38  * These functions may recurse when processing a '*'.
39  */
40 #define	SMB_MATCH_DEPTH_MAX	32
41 
42 #define	SMB_CRC_POLYNOMIAL	0xD8B5D8B5
43 
44 static int smb_match_private(const char *, const char *, int *);
45 static int smb_match_ci_private(const char *, const char *, int *);
46 
47 /*
48  * Returns:
49  * 1	match
50  * 0	no-match
51  */
52 int
53 smb_match(char *patn, char *str)
54 {
55 	int depth = 0;
56 	int rc;
57 
58 	if ((rc = smb_match_private(patn, str, &depth)) == -1)
59 		rc = 0;
60 
61 	return (rc);
62 }
63 
64 /*
65  * The '*' character matches multiple characters.
66  * The '?' character matches a single character.
67  *
68  * If the pattern has trailing '?'s then it matches the specified number
69  * of characters or less.  For example, "x??" matches "xab", "xa" and "x",
70  * but not "xabc".
71  *
72  * Returns:
73  * 1	match
74  * 0	no-match
75  * -1	no-match, too many wildcards in pattern
76  */
77 static int
78 smb_match_private(const char *patn, const char *str, int *depth)
79 {
80 	int rc;
81 
82 	for (;;) {
83 		switch (*patn) {
84 		case '\0':
85 			return (*str == '\0');
86 
87 		case '?':
88 			if (*str != 0) {
89 				str++;
90 				patn++;
91 				continue;
92 			} else {
93 				return (0);
94 			}
95 			/*NOTREACHED*/
96 
97 		case '*':
98 			patn += strspn(patn, "*");
99 			if (*patn == '\0')
100 				return (1);
101 
102 			if ((*depth)++ >= SMB_MATCH_DEPTH_MAX)
103 				return (-1);
104 
105 			while (*str) {
106 				rc = smb_match_private(patn, str, depth);
107 				if (rc != 0)
108 					return (rc);
109 				str++;
110 			}
111 			return (0);
112 
113 		default:
114 			if (*str != *patn)
115 				return (0);
116 			str++;
117 			patn++;
118 			continue;
119 		}
120 	}
121 	/*NOTREACHED*/
122 }
123 
124 int
125 smb_match83(char *patn, char *str83)
126 {
127 	int	avail;
128 	char	*ptr;
129 	char	name83[14];
130 
131 	ptr = name83;
132 	for (avail = SMB_NAME83_BASELEN;
133 	    (avail > 0) && (*patn != '.') && (*patn != 0);
134 	    avail--) {
135 		*(ptr++) = *(patn++);
136 	}
137 	while (avail--)
138 		*(ptr++) = ' ';
139 	*(ptr++) = '.';
140 
141 	if (*patn == '.')
142 		patn++;
143 	else if (*patn != 0)
144 		return (0);
145 
146 	for (avail = SMB_NAME83_EXTLEN; (avail > 0) && (*patn != 0); avail--) {
147 		*(ptr++) = *(patn++);
148 	}
149 	if (*patn != 0)
150 		return (0);
151 
152 	while (avail--)
153 		*(ptr++) = ' ';
154 	*ptr = 0;
155 
156 	return (smb_match_ci(name83, str83));
157 }
158 
159 /*
160  * Returns:
161  * 1	match
162  * 0	no-match
163  */
164 int
165 smb_match_ci(char *patn, char *str)
166 {
167 	int depth = 0;
168 	int rc;
169 
170 	if ((rc = smb_match_ci_private(patn, str, &depth)) == -1)
171 		rc = 0;
172 
173 	return (rc);
174 }
175 
176 /*
177  * The '*' character matches multiple characters.
178  * The '?' character matches a single character.
179  *
180  * If the pattern has trailing '?'s then it matches the specified number
181  * of characters or less.  For example, "x??" matches "xab", "xa" and "x",
182  * but not "xabc".
183  *
184  * Returns:
185  * 1	match
186  * 0	no-match
187  * -1	no-match, too many wildcards in pattern
188  */
189 static int
190 smb_match_ci_private(const char *patn, const char *str, int *depth)
191 {
192 	const char	*p;
193 	smb_wchar_t	wc1, wc2;
194 	int		nbytes1, nbytes2;
195 	int		rc;
196 
197 	/*
198 	 * "<" is a special pattern that matches only those names that do
199 	 * NOT have an extension. "." and ".." are ok.
200 	 */
201 	if (strcmp(patn, "<") == 0) {
202 		if ((strcmp(str, ".") == 0) || (strcmp(str, "..") == 0))
203 			return (1);
204 		if (strchr(str, '.') == 0)
205 			return (1);
206 		return (0);
207 	}
208 
209 	for (;;) {
210 		switch (*patn) {
211 		case '\0':
212 			return (*str == '\0');
213 
214 		case '?':
215 			if (*str != 0) {
216 				str++;
217 				patn++;
218 				continue;
219 			} else {
220 				p = patn;
221 				p += strspn(p, "?");
222 				return ((*p == '\0') ? 1 : 0);
223 			}
224 			/*NOTREACHED*/
225 
226 		case '*':
227 			patn += strspn(patn, "*");
228 			if (*patn == '\0')
229 				return (1);
230 
231 			if ((*depth)++ >= SMB_MATCH_DEPTH_MAX)
232 				return (-1);
233 
234 			while (*str) {
235 				rc = smb_match_ci_private(patn, str, depth);
236 				if (rc != 0)
237 					return (rc);
238 				str++;
239 			}
240 			return (0);
241 
242 		default:
243 			nbytes1 = smb_mbtowc(&wc1, patn, MTS_MB_CHAR_MAX);
244 			nbytes2 = smb_mbtowc(&wc2, str, MTS_MB_CHAR_MAX);
245 			if ((nbytes1 == -1) || (nbytes2 == -1))
246 				return (-1);
247 
248 			if (wc1 != wc2) {
249 				wc1 = smb_tolower(wc1);
250 				wc2 = smb_tolower(wc2);
251 				if (wc1 != wc2)
252 					return (0);
253 			}
254 
255 			patn += nbytes1;
256 			str += nbytes2;
257 			continue;
258 		}
259 	}
260 	/*NOTREACHED*/
261 }
262 
263 uint32_t
264 smb_crc_gen(uint8_t *buf, size_t len)
265 {
266 	uint32_t crc = SMB_CRC_POLYNOMIAL;
267 	uint8_t *p;
268 	int i;
269 
270 	for (p = buf, i = 0; i < len; ++i, ++p) {
271 		crc = (crc ^ (uint32_t)*p) + (crc << 12);
272 
273 		if (crc == 0 || crc == 0xFFFFFFFF)
274 			crc = SMB_CRC_POLYNOMIAL;
275 	}
276 
277 	return (crc);
278 }
279