Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : new hash based name mangling implementation
4 : Copyright (C) Andrew Tridgell 2002
5 : Copyright (C) Simo Sorce 2002
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : /*
22 : this mangling scheme uses the following format
23 :
24 : Annnn~n.AAA
25 :
26 : where nnnnn is a base 36 hash, and A represents characters from the original string
27 :
28 : The hash is taken of the leading part of the long filename, in uppercase
29 :
30 : for simplicity, we only allow ascii characters in 8.3 names
31 : */
32 :
33 : /* hash alghorithm changed to FNV1 by idra@samba.org (Simo Sorce).
34 : * see http://www.isthe.com/chongo/tech/comp/fnv/index.html for a
35 : * discussion on Fowler / Noll / Vo (FNV) Hash by one of it's authors
36 : */
37 :
38 : /*
39 : ===============================================================================
40 : NOTE NOTE NOTE!!!
41 :
42 : This file deliberately uses non-multibyte string functions in many places. This
43 : is *not* a mistake. This code is multi-byte safe, but it gets this property
44 : through some very subtle knowledge of the way multi-byte strings are encoded
45 : and the fact that this mangling algorithm only supports ascii characters in
46 : 8.3 names.
47 :
48 : please don't convert this file to use the *_m() functions!!
49 : ===============================================================================
50 : */
51 :
52 : /*
53 : * ============================================================================
54 : * Whenever you change anything in the FLAG_ or other fields,
55 : * re-initialize the tables char_flags and base_reverse by running the
56 : * init_tables() routine once and dump its results. To do this, a
57 : * single smbd run with
58 : *
59 : * #define DYNAMIC_MANGLE_TABLES 1
60 : *
61 : * and debug level 10 should be sufficient.
62 : * ============================================================================
63 : */
64 :
65 :
66 : #include "includes.h"
67 : #include "smbd/smbd.h"
68 : #include "smbd/globals.h"
69 : #include "../lib/util/memcache.h"
70 : #include "mangle.h"
71 :
72 : #if 1
73 : #define M_DEBUG(level, x) DEBUG(level, x)
74 : #else
75 : #define M_DEBUG(level, x)
76 : #endif
77 :
78 : /* these flags are used to mark characters in as having particular
79 : properties */
80 : #define FLAG_BASECHAR 1
81 : #define FLAG_ASCII 2
82 : #define FLAG_ILLEGAL 4
83 : #define FLAG_WILDCARD 8
84 :
85 : /* the "possible" flags are used as a fast way to find possible DOS
86 : reserved filenames */
87 : #define FLAG_POSSIBLE1 16
88 : #define FLAG_POSSIBLE2 32
89 : #define FLAG_POSSIBLE3 64
90 : #define FLAG_POSSIBLE4 128
91 :
92 : #define FNV1_PRIME 0x01000193
93 : /*the following number is a fnv1 of the string: idra@samba.org 2002 */
94 : #define FNV1_INIT 0xa6b93095
95 :
96 : #define FLAG_CHECK(c, flag) (char_flags[(unsigned char)(c)] & (flag))
97 :
98 : /* these are the characters we use in the 8.3 hash. Must be 36 chars long */
99 : static const char basechars[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
100 : #define base_forward(v) basechars[v]
101 :
102 : /* the list of reserved dos names - all of these are illegal */
103 : static const char * const reserved_names[] =
104 : { "AUX", "CON",
105 : "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
106 : "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
107 : "NUL", "PRN", NULL };
108 :
109 : #define DYNAMIC_MANGLE_TABLES 0
110 :
111 : #if DYNAMIC_MANGLE_TABLES
112 :
113 : /* these tables are used to provide fast tests for characters */
114 : static unsigned char char_flags[256];
115 : static unsigned char base_reverse[256];
116 :
117 : /* initialise the flags table
118 :
119 : we allow only a very restricted set of characters as 'ascii' in this
120 : mangling backend. This isn't a significant problem as modern clients
121 : use the 'long' filenames anyway, and those don't have these
122 : restrictions.
123 : */
124 : static void init_tables(void)
125 : {
126 : int i;
127 :
128 : memset(char_flags, 0, sizeof(char_flags));
129 :
130 : for (i=1;i<128;i++) {
131 : if (i <= 0x1f) {
132 : /* Control characters. */
133 : char_flags[i] |= FLAG_ILLEGAL;
134 : }
135 :
136 : if ((i >= '0' && i <= '9') ||
137 : (i >= 'a' && i <= 'z') ||
138 : (i >= 'A' && i <= 'Z')) {
139 : char_flags[i] |= (FLAG_ASCII | FLAG_BASECHAR);
140 : }
141 : if (strchr("_-$~", i)) {
142 : char_flags[i] |= FLAG_ASCII;
143 : }
144 :
145 : if (strchr("*\\/?<>|\":", i)) {
146 : char_flags[i] |= FLAG_ILLEGAL;
147 : }
148 :
149 : if (strchr("*?\"<>", i)) {
150 : char_flags[i] |= FLAG_WILDCARD;
151 : }
152 : }
153 :
154 : memset(base_reverse, 0, sizeof(base_reverse));
155 : for (i=0;i<36;i++) {
156 : base_reverse[(unsigned char)base_forward(i)] = i;
157 : }
158 :
159 : /* fill in the reserved names flags. These are used as a very
160 : fast filter for finding possible DOS reserved filenames */
161 : for (i=0; reserved_names[i]; i++) {
162 : unsigned char c1, c2, c3, c4;
163 :
164 : c1 = (unsigned char)reserved_names[i][0];
165 : c2 = (unsigned char)reserved_names[i][1];
166 : c3 = (unsigned char)reserved_names[i][2];
167 : c4 = (unsigned char)reserved_names[i][3];
168 :
169 : char_flags[c1] |= FLAG_POSSIBLE1;
170 : char_flags[c2] |= FLAG_POSSIBLE2;
171 : char_flags[c3] |= FLAG_POSSIBLE3;
172 : char_flags[c4] |= FLAG_POSSIBLE4;
173 : char_flags[tolower_m(c1)] |= FLAG_POSSIBLE1;
174 : char_flags[tolower_m(c2)] |= FLAG_POSSIBLE2;
175 : char_flags[tolower_m(c3)] |= FLAG_POSSIBLE3;
176 : char_flags[tolower_m(c4)] |= FLAG_POSSIBLE4;
177 :
178 : char_flags[(unsigned char)'.'] |= FLAG_POSSIBLE4;
179 : }
180 :
181 : #if 0
182 : DEBUG(10, ("char_flags\n"));
183 : dump_data(10, char_flags, sizeof(char_flags));
184 :
185 : DEBUG(10, ("base_reverse\n"));
186 : dump_data(10, base_reverse, sizeof(base_reverse));
187 : #endif
188 : }
189 :
190 : #else /* DYNAMIC_MANGLE_TABLES */
191 :
192 : /*
193 : * These tables were initialized by a single run of the above
194 : * init_tables() routine, dumping the tables and a simple emacs macro.
195 : *
196 : * Technically we could leave out the 0's at the end of the array
197 : * initializers, but I'll leave it in: less surprise.
198 : */
199 :
200 : static const uint8_t char_flags[256] = {
201 : 0x80, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
202 : 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
203 : 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
204 : 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
205 : 0x00, 0x00, 0x0C, 0x00, 0x02, 0x00, 0x00, 0x00,
206 : 0x00, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x80, 0x04,
207 : 0x03, 0x83, 0x83, 0x83, 0x83, 0x03, 0x03, 0x03,
208 : 0x03, 0x03, 0x04, 0x00, 0x0C, 0x00, 0x0C, 0x0C,
209 : 0x00, 0x13, 0x03, 0x53, 0x03, 0x03, 0x03, 0x03,
210 : 0x03, 0x03, 0x03, 0x83, 0x53, 0x43, 0x53, 0x23,
211 : 0x33, 0x03, 0x23, 0x03, 0x43, 0x23, 0x03, 0x03,
212 : 0x43, 0x03, 0x03, 0x00, 0x04, 0x00, 0x00, 0x02,
213 : 0x00, 0x13, 0x03, 0x53, 0x03, 0x03, 0x03, 0x03,
214 : 0x03, 0x03, 0x03, 0x83, 0x53, 0x43, 0x53, 0x23,
215 : 0x33, 0x03, 0x23, 0x03, 0x43, 0x23, 0x03, 0x03,
216 : 0x43, 0x03, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00,
217 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
233 : };
234 :
235 : static const uint8_t base_reverse[256] = {
236 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 : 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
243 : 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 : 0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
245 : 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
246 : 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
247 : 0x21, 0x22, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00,
248 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
251 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
252 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
253 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
257 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
262 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
268 : };
269 :
270 : #endif /* DYNAMIC_MANGLE_TABLES */
271 :
272 : /*
273 : hash a string of the specified length. The string does not need to be
274 : null terminated
275 :
276 : this hash needs to be fast with a low collision rate (what hash doesn't?)
277 : */
278 38555 : static unsigned int mangle_hash(const char *key, unsigned int length)
279 : {
280 : unsigned int value;
281 : unsigned int i;
282 : fstring str;
283 :
284 : /* we have to uppercase here to ensure that the mangled name
285 : doesn't depend on the case of the long name. Note that this
286 : is the only place where we need to use a multi-byte string
287 : function */
288 38555 : length = MIN(length,sizeof(fstring)-1);
289 38683 : strncpy(str, key, length);
290 38555 : str[length] = 0;
291 38555 : (void)strupper_m(str);
292 :
293 : /* the length of a multi-byte string can change after a strupper_m */
294 38555 : length = strlen(str);
295 :
296 : /* Set the initial value from the key size. */
297 1219826 : for (value = FNV1_INIT, i=0; i < length; i++) {
298 1181271 : value *= (unsigned int)FNV1_PRIME;
299 1181271 : value ^= (unsigned int)(str[i]);
300 : }
301 :
302 : /* note that we force it to a 31 bit hash, to keep within the limits
303 : of the 36^6 mangle space */
304 38555 : return value & ~0x80000000;
305 : }
306 :
307 : /*
308 : insert an entry into the prefix cache. The string might not be null
309 : terminated */
310 33803 : static void cache_insert(const char *prefix, int length, unsigned int hash)
311 : {
312 33803 : char *str = SMB_STRNDUP(prefix, length);
313 :
314 33803 : if (str == NULL) {
315 0 : return;
316 : }
317 :
318 33803 : memcache_add(smbd_memcache(), MANGLE_HASH2_CACHE,
319 : data_blob_const(&hash, sizeof(hash)),
320 33803 : data_blob_const(str, length+1));
321 33803 : SAFE_FREE(str);
322 : }
323 :
324 : /*
325 : lookup an entry in the prefix cache. Return NULL if not found.
326 : */
327 196 : static char *cache_lookup(TALLOC_CTX *mem_ctx, unsigned int hash)
328 : {
329 : DATA_BLOB value;
330 :
331 196 : if (!memcache_lookup(smbd_memcache(), MANGLE_HASH2_CACHE,
332 : data_blob_const(&hash, sizeof(hash)), &value)) {
333 0 : return NULL;
334 : }
335 :
336 196 : SMB_ASSERT((value.length > 0)
337 : && (value.data[value.length-1] == '\0'));
338 :
339 196 : return talloc_strdup(mem_ctx, (char *)value.data);
340 : }
341 :
342 :
343 : /*
344 : determine if a string is possibly in a mangled format, ignoring
345 : case
346 :
347 : In this algorithm, mangled names use only pure ascii characters (no
348 : multi-byte) so we can avoid doing a UCS2 conversion
349 : */
350 873403 : static bool is_mangled_component(const char *name, size_t len)
351 : {
352 : unsigned int i;
353 :
354 873403 : M_DEBUG(10,("is_mangled_component %s (len %lu) ?\n", name, (unsigned long)len));
355 :
356 : /* check the length */
357 873403 : if (len > 12 || len < 8)
358 572854 : return False;
359 :
360 : /* the best distinguishing characteristic is the ~ */
361 299652 : if (name[6] != '~')
362 297822 : return False;
363 :
364 : /* check extension */
365 556 : if (len > 8) {
366 120 : if (name[8] != '.')
367 0 : return False;
368 400 : for (i=9; name[i] && i < len; i++) {
369 280 : if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
370 0 : return False;
371 : }
372 : }
373 : }
374 :
375 : /* check lead characters */
376 1112 : for (i=0;i<mangle_prefix;i++) {
377 556 : if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
378 0 : return False;
379 : }
380 : }
381 :
382 : /* check rest of hash */
383 556 : if (! FLAG_CHECK(name[7], FLAG_BASECHAR)) {
384 0 : return False;
385 : }
386 3336 : for (i=mangle_prefix;i<6;i++) {
387 2780 : if (! FLAG_CHECK(name[i], FLAG_BASECHAR)) {
388 0 : return False;
389 : }
390 : }
391 :
392 556 : M_DEBUG(10,("is_mangled_component %s (len %lu) -> yes\n", name, (unsigned long)len));
393 :
394 556 : return True;
395 : }
396 :
397 :
398 :
399 : /*
400 : determine if a string is possibly in a mangled format, ignoring
401 : case
402 :
403 : In this algorithm, mangled names use only pure ascii characters (no
404 : multi-byte) so we can avoid doing a UCS2 conversion
405 :
406 : NOTE! This interface must be able to handle a path with unix
407 : directory separators. It should return true if any component is
408 : mangled
409 : */
410 867434 : static bool is_mangled(const char *name, const struct share_params *parm)
411 : {
412 : const char *p;
413 : const char *s;
414 :
415 867434 : M_DEBUG(10,("is_mangled %s ?\n", name));
416 :
417 871238 : for (s=name; (p=strchr(s, '/')); s=p+1) {
418 5975 : if (is_mangled_component(s, PTR_DIFF(p, s))) {
419 6 : return True;
420 : }
421 : }
422 :
423 : /* and the last part ... */
424 867428 : return is_mangled_component(s,strlen(s));
425 : }
426 :
427 :
428 : /*
429 : see if a filename is an allowable 8.3 name to return to the client.
430 : Note this is not testing if this is a valid Samba mangled name, so
431 : the rules are different for is_mangled.
432 :
433 : we are only going to allow ascii characters in 8.3 names, as this
434 : simplifies things greatly (it means that we know the string won't
435 : get larger when converted from UNIX to DOS formats)
436 : */
437 :
438 : static const char force_shortname_chars[] = " +,[];=";
439 :
440 534660 : static bool is_8_3(const char *name, bool check_case, bool allow_wildcards, const struct share_params *p)
441 : {
442 : int len, i;
443 : char *dot_p;
444 :
445 : /* as a special case, the names '.' and '..' are allowable 8.3 names */
446 534660 : if (name[0] == '.') {
447 24094 : if (!name[1] || (name[1] == '.' && !name[2])) {
448 22494 : return True;
449 : }
450 : }
451 :
452 : /* the simplest test is on the overall length of the
453 : filename. Note that we deliberately use the ascii string
454 : length (not the multi-byte one) as it is faster, and gives us
455 : the result we need in this case. Using strlen_m would not
456 : only be slower, it would be incorrect */
457 512076 : len = strlen(name);
458 512076 : if (len > 12)
459 70164 : return False;
460 :
461 : /* find the '.'. Note that once again we use the non-multibyte
462 : function */
463 441710 : dot_p = strchr(name, '.');
464 :
465 441710 : if (!dot_p) {
466 : /* if the name doesn't contain a '.' then its length
467 : must be less than 8 */
468 360206 : if (len > 8) {
469 14695 : return False;
470 : }
471 : } else {
472 : int prefix_len, suffix_len;
473 :
474 : /* if it does contain a dot then the prefix must be <=
475 : 8 and the suffix <= 3 in length */
476 81504 : prefix_len = PTR_DIFF(dot_p, name);
477 81504 : suffix_len = len - (prefix_len+1);
478 :
479 81504 : if (prefix_len > 8 || suffix_len > 3 || suffix_len == 0) {
480 4764 : return False;
481 : }
482 :
483 : /* a 8.3 name cannot contain more than 1 '.' */
484 76447 : if (strchr(dot_p+1, '.')) {
485 0 : return False;
486 : }
487 : }
488 :
489 : /* the length are all OK. Now check to see if the characters themselves are OK */
490 3274106 : for (i=0; name[i]; i++) {
491 2859766 : if (FLAG_CHECK(name[i], FLAG_ILLEGAL)) {
492 6140 : return false;
493 : }
494 : /* note that we may allow wildcard petterns! */
495 2853581 : if (!allow_wildcards && FLAG_CHECK(name[i], FLAG_WILDCARD)) {
496 0 : return false;
497 : }
498 2853581 : if (((unsigned char)name[i]) > 0x7e) {
499 100 : return false;
500 : }
501 2853481 : if (strchr(force_shortname_chars, name[i])) {
502 1004 : return false;
503 : }
504 : }
505 :
506 : /* it is a good 8.3 name */
507 414385 : return True;
508 : }
509 :
510 :
511 : /*
512 : reset the mangling cache on a smb.conf reload. This only really makes sense for
513 : mangling backends that have parameters in smb.conf, and as this backend doesn't
514 : this is a NULL operation
515 : */
516 1360 : static void mangle_reset(void)
517 : {
518 : /* noop */
519 1360 : }
520 :
521 :
522 : /*
523 : try to find a 8.3 name in the cache, and if found then
524 : replace the string with the original long name.
525 : */
526 196 : static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
527 : const char *name,
528 : char **pp_out, /* talloced on the given context. */
529 : const struct share_params *p)
530 : {
531 : unsigned int hash, multiplier;
532 : unsigned int i;
533 : char *prefix;
534 : char extension[4];
535 :
536 196 : *pp_out = NULL;
537 :
538 : /* make sure that this is a mangled name from this cache */
539 196 : if (!is_mangled(name, p)) {
540 0 : M_DEBUG(10,("lookup_name_from_8_3: %s -> not mangled\n", name));
541 0 : return False;
542 : }
543 :
544 : /* we need to extract the hash from the 8.3 name */
545 196 : hash = base_reverse[(unsigned char)name[7]];
546 1176 : for (multiplier=36, i=5;i>=mangle_prefix;i--) {
547 980 : unsigned int v = base_reverse[(unsigned char)name[i]];
548 980 : hash += multiplier * v;
549 980 : multiplier *= 36;
550 : }
551 :
552 : /* now look in the prefix cache for that hash */
553 196 : prefix = cache_lookup(ctx, hash);
554 196 : if (!prefix) {
555 0 : M_DEBUG(10,("lookup_name_from_8_3: %s -> %08X -> not found\n",
556 : name, hash));
557 0 : return False;
558 : }
559 :
560 : /* we found it - construct the full name */
561 196 : if (name[8] == '.') {
562 45 : strncpy(extension, name+9, 3);
563 45 : extension[3] = 0;
564 : } else {
565 151 : extension[0] = 0;
566 : }
567 :
568 196 : if (extension[0]) {
569 45 : M_DEBUG(10,("lookup_name_from_8_3: %s -> %s.%s\n",
570 : name, prefix, extension));
571 45 : *pp_out = talloc_asprintf(ctx, "%s.%s", prefix, extension);
572 : } else {
573 151 : M_DEBUG(10,("lookup_name_from_8_3: %s -> %s\n", name, prefix));
574 151 : *pp_out = talloc_strdup(ctx, prefix);
575 : }
576 :
577 196 : TALLOC_FREE(prefix);
578 :
579 196 : if (!*pp_out) {
580 0 : M_DEBUG(0,("talloc_fail"));
581 0 : return False;
582 : }
583 :
584 196 : return True;
585 : }
586 :
587 : /*
588 : look for a DOS reserved name
589 : */
590 548570 : static bool is_reserved_name(const char *name)
591 : {
592 564986 : if (FLAG_CHECK(name[0], FLAG_POSSIBLE1) &&
593 26455 : FLAG_CHECK(name[1], FLAG_POSSIBLE2) &&
594 12266 : FLAG_CHECK(name[2], FLAG_POSSIBLE3) &&
595 4486 : FLAG_CHECK(name[3], FLAG_POSSIBLE4)) {
596 : /* a likely match, scan the lot */
597 : int i;
598 33212 : for (i=0; reserved_names[i]; i++) {
599 31768 : int len = strlen(reserved_names[i]);
600 : /* note that we match on COM1 as well as COM1.foo */
601 31768 : if (strnequal(name, reserved_names[i], len) &&
602 0 : (name[len] == '.' || name[len] == 0)) {
603 0 : return True;
604 : }
605 : }
606 : }
607 :
608 548257 : return False;
609 : }
610 :
611 : /*
612 : See if a filename is a legal long filename.
613 : A filename ending in a '.' is not legal unless it's "." or "..". JRA.
614 : A filename ending in ' ' is not legal either. See bug id #2769.
615 : */
616 :
617 548570 : static bool is_legal_name(const char *name)
618 : {
619 548570 : const char *dot_pos = NULL;
620 548570 : bool alldots = True;
621 548570 : size_t numdots = 0;
622 :
623 8247583 : while (*name) {
624 7239533 : if (((unsigned int)name[0]) > 128 && (name[1] != 0)) {
625 : /* Possible start of mb character. */
626 266 : size_t size = 0;
627 266 : (void)next_codepoint(name, &size);
628 : /*
629 : * Note that we're only looking for multibyte
630 : * encoding here. No encoding with a length > 1
631 : * contains invalid characters.
632 : */
633 266 : if (size > 1) {
634 : /* Was a mb string. */
635 46 : name += size;
636 46 : continue;
637 : }
638 : }
639 :
640 7239487 : if (FLAG_CHECK(name[0], FLAG_ILLEGAL)) {
641 6220 : return False;
642 : }
643 7233222 : if (name[0] == '.') {
644 294194 : dot_pos = name;
645 294194 : numdots++;
646 : } else {
647 6937114 : alldots = False;
648 : }
649 7233222 : if ((name[0] == ' ') && (name[1] == '\0')) {
650 : /* Can't end in ' ' */
651 0 : return False;
652 : }
653 7233222 : name++;
654 : }
655 :
656 542305 : if (dot_pos) {
657 280910 : if (alldots && (numdots == 1 || numdots == 2))
658 25992 : return True; /* . or .. is a valid name */
659 :
660 : /* A valid long name cannot end in '.' */
661 254828 : if (dot_pos[1] == '\0')
662 13 : return False;
663 : }
664 516210 : return True;
665 : }
666 :
667 507999 : static bool must_mangle(const char *name,
668 : const struct share_params *p)
669 : {
670 507999 : if (is_reserved_name(name)) {
671 0 : return True;
672 : }
673 507999 : return !is_legal_name(name);
674 : }
675 :
676 : /*
677 : the main forward mapping function, which converts a long filename to
678 : a 8.3 name
679 :
680 : if cache83 is not set then we don't cache the result
681 :
682 : */
683 40571 : static bool hash2_name_to_8_3(const char *name,
684 : char new_name[13],
685 : bool cache83,
686 : int default_case,
687 : const struct share_params *p)
688 : {
689 : char *dot_p;
690 : char lead_chars[7];
691 : char extension[4];
692 : unsigned int extension_length, i;
693 : unsigned int prefix_len;
694 : unsigned int hash, v;
695 :
696 : /* reserved names are handled specially */
697 40571 : if (!is_reserved_name(name)) {
698 : /* if the name is already a valid 8.3 name then we don't need to
699 : * change anything */
700 40571 : if (is_legal_name(name) && is_8_3(name, False, False, p)) {
701 2016 : strlcpy(new_name, name, 13);
702 2016 : return True;
703 : }
704 : }
705 :
706 : /* find the '.' if any */
707 38555 : dot_p = strrchr(name, '.');
708 :
709 38555 : if (dot_p) {
710 : /* if the extension contains any illegal characters or
711 : is too long or zero length then we treat it as part
712 : of the prefix */
713 65179 : for (i=0; i<4 && dot_p[i+1]; i++) {
714 50767 : if (! FLAG_CHECK(dot_p[i+1], FLAG_ASCII)) {
715 462 : dot_p = NULL;
716 462 : break;
717 : }
718 : }
719 14874 : if (i == 0 || i == 4) {
720 7883 : dot_p = NULL;
721 : }
722 : }
723 :
724 : /* the leading characters in the mangled name is taken from
725 : the first characters of the name, if they are ascii otherwise
726 : '_' is used
727 : */
728 77110 : for (i=0;i<mangle_prefix && name[i];i++) {
729 38555 : lead_chars[i] = name[i];
730 38555 : if (! FLAG_CHECK(lead_chars[i], FLAG_ASCII)) {
731 6706 : lead_chars[i] = '_';
732 : }
733 38555 : lead_chars[i] = toupper_m(lead_chars[i]);
734 : }
735 38427 : for (;i<mangle_prefix;i++) {
736 0 : lead_chars[i] = '_';
737 : }
738 :
739 : /* the prefix is anything up to the first dot */
740 38555 : if (dot_p) {
741 6991 : prefix_len = PTR_DIFF(dot_p, name);
742 : } else {
743 31564 : prefix_len = strlen(name);
744 : }
745 :
746 : /* the extension of the mangled name is taken from the first 3
747 : ascii chars after the dot */
748 38555 : extension_length = 0;
749 38555 : if (dot_p) {
750 27644 : for (i=1; extension_length < 3 && dot_p[i]; i++) {
751 20657 : char c = dot_p[i];
752 20657 : if (FLAG_CHECK(c, FLAG_ASCII)) {
753 20657 : extension[extension_length++] =
754 20657 : toupper_m(c);
755 : }
756 : }
757 : }
758 :
759 : /* find the hash for this prefix */
760 38555 : v = hash = mangle_hash(name, prefix_len);
761 :
762 : /* now form the mangled name. */
763 77110 : for (i=0;i<mangle_prefix;i++) {
764 38555 : new_name[i] = lead_chars[i];
765 : }
766 38555 : new_name[7] = base_forward(v % 36);
767 38555 : new_name[6] = '~';
768 231330 : for (i=5; i>=mangle_prefix; i--) {
769 192775 : v = v / 36;
770 192775 : new_name[i] = base_forward(v % 36);
771 : }
772 :
773 : /* add the extension */
774 38555 : if (extension_length) {
775 6991 : new_name[8] = '.';
776 6995 : memcpy(&new_name[9], extension, extension_length);
777 6991 : new_name[9+extension_length] = 0;
778 : } else {
779 31564 : new_name[8] = 0;
780 : }
781 :
782 38555 : if (cache83) {
783 : /* put it in the cache */
784 33803 : cache_insert(name, prefix_len, hash);
785 : }
786 :
787 38555 : M_DEBUG(10,("hash2_name_to_8_3: %s -> %08X -> %s (cache=%d)\n",
788 : name, hash, new_name, cache83));
789 :
790 38427 : return True;
791 : }
792 :
793 : /*
794 : the following provides the abstraction layer to make it easier
795 : to drop in an alternative mangling implementation */
796 : static const struct mangle_fns mangle_hash2_fns = {
797 : mangle_reset,
798 : is_mangled,
799 : must_mangle,
800 : is_8_3,
801 : lookup_name_from_8_3,
802 : hash2_name_to_8_3
803 : };
804 :
805 : /* return the methods for this mangling implementation */
806 73 : const struct mangle_fns *mangle_hash2_init(void)
807 : {
808 : /* the mangle prefix can only be in the mange 1 to 6 */
809 73 : mangle_prefix = lp_mangle_prefix();
810 73 : if (mangle_prefix > 6) {
811 0 : mangle_prefix = 6;
812 : }
813 73 : if (mangle_prefix < 1) {
814 0 : mangle_prefix = 1;
815 : }
816 :
817 : #if DYNAMIC_MANGLE_TABLES
818 : init_tables();
819 : #endif
820 71 : mangle_reset();
821 :
822 73 : return &mangle_hash2_fns;
823 : }
824 :
825 112 : static void posix_mangle_reset(void)
826 112 : {;}
827 :
828 702 : static bool posix_is_mangled(const char *s, const struct share_params *p)
829 : {
830 702 : return False;
831 : }
832 :
833 2039 : static bool posix_must_mangle(const char *s, const struct share_params *p)
834 : {
835 2039 : return False;
836 : }
837 :
838 2047 : static bool posix_is_8_3(const char *fname,
839 : bool check_case,
840 : bool allow_wildcards,
841 : const struct share_params *p)
842 : {
843 2047 : return False;
844 : }
845 :
846 0 : static bool posix_lookup_name_from_8_3(TALLOC_CTX *ctx,
847 : const char *in,
848 : char **out, /* talloced on the given context. */
849 : const struct share_params *p)
850 : {
851 0 : return False;
852 : }
853 :
854 2055 : static bool posix_name_to_8_3(const char *in,
855 : char out[13],
856 : bool cache83,
857 : int default_case,
858 : const struct share_params *p)
859 : {
860 2055 : memset(out, '\0', 13);
861 2055 : return True;
862 : }
863 :
864 : /* POSIX paths backend - no mangle. */
865 : static const struct mangle_fns posix_mangle_fns = {
866 : posix_mangle_reset,
867 : posix_is_mangled,
868 : posix_must_mangle,
869 : posix_is_8_3,
870 : posix_lookup_name_from_8_3,
871 : posix_name_to_8_3
872 : };
873 :
874 112 : const struct mangle_fns *posix_mangle_init(void)
875 : {
876 112 : return &posix_mangle_fns;
877 : }
|