Print this page
NEX-19025 CIFS gets confused with filenames containing enhanced Unicode
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
and: (fix build, check-rtime)
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-2460 libfksmbd should not link with libsmb
re #6854 FindFirstFile,FindFirstFileEx,... are not working correctly on Nexenta CIFS-shares
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/common/smbsrv/smb_match.c
+++ new/usr/src/common/smbsrv/smb_match.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
28 28 #include <stdlib.h>
29 29 #include <string.h>
30 30 #else
31 31 #include <sys/types.h>
32 32 #include <sys/systm.h>
33 33 #include <sys/sunddi.h>
34 34 #endif
35 35 #include <smbsrv/string.h>
36 36 #include <smbsrv/smb.h>
37 37
38 38 /*
39 39 * Maximum recursion depth for the wildcard match functions.
40 40 * These functions may recurse when processing a '*'.
41 41 */
42 42 #define SMB_MATCH_DEPTH_MAX 32
43 43
44 44 struct match_priv {
45 45 int depth;
46 46 boolean_t ci;
47 47 };
48 48
49 49 static int smb_match_private(const char *, const char *, struct match_priv *);
50 50
51 51 static const char smb_wildcards[] = "*?<>\"";
52 52
53 53 /*
54 54 * Return B_TRUE if pattern contains wildcards
55 55 */
56 56 boolean_t
57 57 smb_contains_wildcards(const char *pattern)
58 58 {
59 59
60 60 return (strpbrk(pattern, smb_wildcards) != NULL);
61 61 }
62 62
63 63 /*
64 64 * NT-compatible file name match function. [MS-FSA 3.1.4.4]
65 65 * Returns TRUE if there is a match.
66 66 */
67 67 boolean_t
68 68 smb_match(const char *p, const char *s, boolean_t ci)
69 69 {
70 70 struct match_priv priv;
71 71 int rc;
72 72
73 73 /*
74 74 * Optimize common patterns that match everything:
75 75 * ("*", "<\"*") That second one is the converted
76 76 * form of "*.*" after smb_convert_wildcards() does
77 77 * its work on it for an old LM client. Note that a
78 78 * plain "*.*" never gets this far.
79 79 */
80 80 if (p[0] == '*' && p[1] == '\0')
81 81 return (B_TRUE);
82 82 if (p[0] == '<' && p[1] == '\"' && p[2] == '*' && p[3] == '\0')
83 83 return (B_TRUE);
84 84
85 85 /*
86 86 * Match string ".." as if "." This is Windows behavior
87 87 * (not mentioned in MS-FSA) that was determined using
88 88 * the Samba masktest program.
89 89 */
90 90 if (s[0] == '.' && s[1] == '.' && s[2] == '\0')
91 91 s++;
92 92
93 93 /*
94 94 * Optimize simple patterns (no wildcards)
95 95 */
96 96 if (NULL == strpbrk(p, smb_wildcards)) {
97 97 if (ci)
98 98 rc = smb_strcasecmp(p, s, 0);
99 99 else
100 100 rc = strcmp(p, s);
101 101 return (rc == 0);
102 102 }
103 103
104 104 /*
105 105 * Do real wildcard match.
106 106 */
107 107 priv.depth = 0;
108 108 priv.ci = ci;
109 109 rc = smb_match_private(p, s, &priv);
110 110 return (rc == 1);
111 111 }
112 112
113 113 /*
114 114 * Internal file name match function. [MS-FSA 3.1.4.4]
115 115 * This does the full expression evaluation.
116 116 *
117 117 * '*' matches zero of more of any characters.
118 118 * '?' matches exactly one of any character.
119 119 * '<' matches any string up through the last dot or EOS.
120 120 * '>' matches any one char not a dot, dot at EOS, or EOS.
121 121 * '"' matches a dot, or EOS.
122 122 *
123 123 * Returns:
124 124 * 1 match
125 125 * 0 no-match
126 126 * -1 no-match, error (illseq, too many wildcards in pattern, ...)
127 127 *
128 128 * Note that both the pattern and the string are in multi-byte form.
129 129 *
130 130 * The implementation of this is quite tricky. First note that it
131 131 * can call itself recursively, though it limits the recursion depth.
132 132 * Each switch case in the while loop can basically do one of three
133 133 * things: (a) return "Yes, match", (b) return "not a match", or
134 134 * continue processing the match pattern. The cases for wildcards
|
↓ open down ↓ |
134 lines elided |
↑ open up ↑ |
135 135 * that may match a variable number of characters ('*' and '<') do
136 136 * recursive calls, looking for a match of the remaining pattern,
137 137 * starting at the current and later positions in the string.
138 138 */
139 139 static int
140 140 smb_match_private(const char *pat, const char *str, struct match_priv *priv)
141 141 {
142 142 const char *limit;
143 143 char pc; /* current pattern char */
144 144 int rc;
145 - smb_wchar_t wcpat, wcstr; /* current wchar in pat, str */
145 + uint32_t wcpat, wcstr; /* current wchar in pat, str */
146 146 int nbpat, nbstr; /* multi-byte length of it */
147 147
148 148 if (priv->depth >= SMB_MATCH_DEPTH_MAX)
149 149 return (-1);
150 150
151 151 /*
152 152 * Advance over one multi-byte char, used in cases like
153 153 * '?' or '>' where "match one character" needs to be
154 154 * interpreted as "match one multi-byte sequence".
155 155 *
156 156 * This macro needs to consume the semicolon following
157 157 * each place it appears, so this is carefully written
158 158 * as an if/else with a missing semicolon at the end.
159 159 */
160 160 #define ADVANCE(str) \
161 161 if ((nbstr = smb_mbtowc(NULL, str, MTS_MB_CHAR_MAX)) < 1) \
162 162 return (-1); \
163 163 else \
164 164 str += nbstr /* no ; */
165 165
166 166 /*
167 167 * We move pat forward in each switch case so that the
168 168 * default case can move it by a whole multi-byte seq.
169 169 */
170 170 while ((pc = *pat) != '\0') {
171 171 switch (pc) {
172 172
173 173 case '?': /* exactly one of any character */
174 174 pat++;
175 175 if (*str != '\0') {
176 176 ADVANCE(str);
177 177 continue;
178 178 }
179 179 /* EOS: no-match */
180 180 return (0);
181 181
182 182 case '*': /* zero or more of any characters */
183 183 pat++;
184 184 /* Optimize '*' at end of pattern. */
185 185 if (*pat == '\0')
186 186 return (1); /* match */
187 187 while (*str != '\0') {
188 188 priv->depth++;
189 189 rc = smb_match_private(pat, str, priv);
190 190 priv->depth--;
191 191 if (rc != 0)
192 192 return (rc); /* match */
193 193 ADVANCE(str);
194 194 }
195 195 continue;
196 196
197 197 case '<': /* any string up through the last dot or EOS */
198 198 pat++;
199 199 if ((limit = strrchr(str, '.')) != NULL)
200 200 limit++;
201 201 while (*str != '\0' && str != limit) {
202 202 priv->depth++;
203 203 rc = smb_match_private(pat, str, priv);
204 204 priv->depth--;
205 205 if (rc != 0)
206 206 return (rc); /* match */
207 207 ADVANCE(str);
208 208 }
209 209 continue;
210 210
211 211 case '>': /* anything not a dot, dot at EOS, or EOS */
212 212 pat++;
213 213 if (*str == '.') {
214 214 if (str[1] == '\0') {
215 215 /* dot at EOS */
216 216 str++; /* ADVANCE over '.' */
217 217 continue;
218 218 }
219 219 /* dot NOT at EOS: no-match */
220 220 return (0);
221 221 }
222 222 if (*str != '\0') {
223 223 /* something not a dot */
224 224 ADVANCE(str);
225 225 continue;
226 226 }
227 227 continue;
228 228
229 229 case '\"': /* dot, or EOS */
230 230 pat++;
231 231 if (*str == '.') {
232 232 str++; /* ADVANCE over '.' */
233 233 continue;
234 234 }
235 235 if (*str == '\0') {
236 236 continue;
237 237 }
238 238 /* something else: no-match */
239 239 return (0);
240 240
241 241 default: /* not a wildcard */
242 242 nbpat = smb_mbtowc(&wcpat, pat, MTS_MB_CHAR_MAX);
243 243 nbstr = smb_mbtowc(&wcstr, str, MTS_MB_CHAR_MAX);
244 244 /* make sure we advance */
245 245 if (nbpat < 1 || nbstr < 1)
246 246 return (-1);
247 247 if (wcpat == wcstr) {
248 248 pat += nbpat;
249 249 str += nbstr;
250 250 continue;
251 251 }
252 252 if (priv->ci) {
253 253 wcpat = smb_tolower(wcpat);
254 254 wcstr = smb_tolower(wcstr);
255 255 if (wcpat == wcstr) {
256 256 pat += nbpat;
257 257 str += nbstr;
258 258 continue;
259 259 }
260 260 }
261 261 return (0); /* no-match */
262 262 }
263 263 }
264 264 return (*str == '\0');
265 265 }
|
↓ open down ↓ |
110 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX