Home | History | Annotate | Download | only in smbsrv
      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