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