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.
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.
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]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
27 #if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
31 #include <sys/types.h>
32 #include <sys/systm.h>
33 #include <sys/sunddi.h>
35 #include <smbsrv/string.h>
36 #include <smbsrv/smb.h>
39 * Maximum recursion depth for the wildcard match functions.
40 * These functions may recurse when processing a '*'.
42 #define SMB_MATCH_DEPTH_MAX 32
49 static int smb_match_private(const char *, const char *, struct match_priv
*);
51 static const char smb_wildcards
[] = "*?<>\"";
54 * Return B_TRUE if pattern contains wildcards
57 smb_contains_wildcards(const char *pattern
)
60 return (strpbrk(pattern
, smb_wildcards
) != NULL
);
64 * NT-compatible file name match function. [MS-FSA 3.1.4.4]
65 * Returns TRUE if there is a match.
68 smb_match(const char *p
, const char *s
, boolean_t ci
)
70 struct match_priv priv
;
74 * Optimize common patterns that match everything:
75 * ("*", "<\"*") That second one is the converted
76 * form of "*.*" after smb_convert_wildcards() does
77 * its work on it for an old LM client. Note that a
78 * plain "*.*" never gets this far.
80 if (p
[0] == '*' && p
[1] == '\0')
82 if (p
[0] == '<' && p
[1] == '\"' && p
[2] == '*' && p
[3] == '\0')
86 * Match string ".." as if "." This is Windows behavior
87 * (not mentioned in MS-FSA) that was determined using
88 * the Samba masktest program.
90 if (s
[0] == '.' && s
[1] == '.' && s
[2] == '\0')
94 * Optimize simple patterns (no wildcards)
96 if (NULL
== strpbrk(p
, smb_wildcards
)) {
98 rc
= smb_strcasecmp(p
, s
, 0);
105 * Do real wildcard match.
109 rc
= smb_match_private(p
, s
, &priv
);
114 * Internal file name match function. [MS-FSA 3.1.4.4]
115 * This does the full expression evaluation.
117 * '*' matches zero of more of any characters.
118 * '?' matches exactly one of any character.
119 * '<' matches any string up through the last dot or EOS.
120 * '>' matches any one char not a dot, dot at EOS, or EOS.
121 * '"' matches a dot, or EOS.
126 * -1 no-match, error (illseq, too many wildcards in pattern, ...)
128 * Note that both the pattern and the string are in multi-byte form.
130 * The implementation of this is quite tricky. First note that it
131 * can call itself recursively, though it limits the recursion depth.
132 * Each switch case in the while loop can basically do one of three
133 * things: (a) return "Yes, match", (b) return "not a match", or
134 * continue processing the match pattern. The cases for wildcards
135 * that may match a variable number of characters ('*' and '<') do
136 * recursive calls, looking for a match of the remaining pattern,
137 * starting at the current and later positions in the string.
140 smb_match_private(const char *pat
, const char *str
, struct match_priv
*priv
)
143 char pc
; /* current pattern char */
145 smb_wchar_t wcpat
, wcstr
; /* current wchar in pat, str */
146 int nbpat
, nbstr
; /* multi-byte length of it */
148 if (priv
->depth
>= SMB_MATCH_DEPTH_MAX
)
152 * Advance over one multi-byte char, used in cases like
153 * '?' or '>' where "match one character" needs to be
154 * interpreted as "match one multi-byte sequence".
156 * This macro needs to consume the semicolon following
157 * each place it appears, so this is carefully written
158 * as an if/else with a missing semicolon at the end.
160 #define ADVANCE(str) \
161 if ((nbstr = smb_mbtowc(NULL, str, MTS_MB_CHAR_MAX)) < 1) \
164 str += nbstr /* no ; */
167 * We move pat forward in each switch case so that the
168 * default case can move it by a whole multi-byte seq.
170 while ((pc
= *pat
) != '\0') {
173 case '?': /* exactly one of any character */
182 case '*': /* zero or more of any characters */
184 /* Optimize '*' at end of pattern. */
186 return (1); /* match */
187 while (*str
!= '\0') {
189 rc
= smb_match_private(pat
, str
, priv
);
192 return (rc
); /* match */
197 case '<': /* any string up through the last dot or EOS */
199 if ((limit
= strrchr(str
, '.')) != NULL
)
201 while (*str
!= '\0' && str
!= limit
) {
203 rc
= smb_match_private(pat
, str
, priv
);
206 return (rc
); /* match */
211 case '>': /* anything not a dot, dot at EOS, or EOS */
214 if (str
[1] == '\0') {
216 str
++; /* ADVANCE over '.' */
219 /* dot NOT at EOS: no-match */
223 /* something not a dot */
229 case '\"': /* dot, or EOS */
232 str
++; /* ADVANCE over '.' */
238 /* something else: no-match */
241 default: /* not a wildcard */
242 nbpat
= smb_mbtowc(&wcpat
, pat
, MTS_MB_CHAR_MAX
);
243 nbstr
= smb_mbtowc(&wcstr
, str
, MTS_MB_CHAR_MAX
);
244 /* make sure we advance */
245 if (nbpat
< 1 || nbstr
< 1)
247 if (wcpat
== wcstr
) {
253 wcpat
= smb_tolower(wcpat
);
254 wcstr
= smb_tolower(wcstr
);
255 if (wcpat
== wcstr
) {
261 return (0); /* no-match */
264 return (*str
== '\0');