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 algorithm 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 51568 : static unsigned int mangle_hash(const char *key, unsigned int length)
279 : {
280 178 : unsigned int value;
281 178 : unsigned int i;
282 178 : 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 51568 : length = MIN(length,sizeof(fstring)-1);
289 51568 : strncpy(str, key, length);
290 51568 : str[length] = 0;
291 51568 : (void)strupper_m(str);
292 :
293 : /* the length of a multi-byte string can change after a strupper_m */
294 51568 : length = strlen(str);
295 :
296 : /* Set the initial value from the key size. */
297 1399792 : for (value = FNV1_INIT, i=0; i < length; i++) {
298 1348224 : value *= (unsigned int)FNV1_PRIME;
299 1348224 : 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 51568 : return value & ~0x80000000;
305 : }
306 :
307 : /*
308 : insert an entry into the prefix cache. The string might not be null
309 : terminated */
310 50629 : static void cache_insert(const char *prefix, int length, unsigned int hash)
311 : {
312 50629 : char *str = SMB_STRNDUP(prefix, length);
313 :
314 50629 : if (str == NULL) {
315 0 : return;
316 : }
317 :
318 50629 : memcache_add(smbd_memcache(), MANGLE_HASH2_CACHE,
319 : data_blob_const(&hash, sizeof(hash)),
320 50629 : data_blob_const(str, length+1));
321 50629 : SAFE_FREE(str);
322 : }
323 :
324 : /*
325 : lookup an entry in the prefix cache. Return NULL if not found.
326 : */
327 218 : static char *cache_lookup(TALLOC_CTX *mem_ctx, unsigned int hash)
328 : {
329 0 : DATA_BLOB value;
330 :
331 218 : if (!memcache_lookup(smbd_memcache(), MANGLE_HASH2_CACHE,
332 : data_blob_const(&hash, sizeof(hash)), &value)) {
333 32 : return NULL;
334 : }
335 :
336 186 : SMB_ASSERT((value.length > 0)
337 : && (value.data[value.length-1] == '\0'));
338 :
339 186 : 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 543468 : static bool is_mangled_component(const char *name, size_t len)
351 : {
352 1759 : unsigned int i;
353 :
354 543468 : M_DEBUG(10,("is_mangled_component %s (len %lu) ?\n", name, (unsigned long)len));
355 :
356 : /* check the length */
357 543468 : if (len > 12 || len < 8)
358 369439 : return False;
359 :
360 : /* the best distinguishing characteristic is the ~ */
361 173038 : if (name[6] != '~')
362 171830 : return False;
363 :
364 : /* check extension */
365 440 : if (len > 8) {
366 60 : if (name[8] != '.')
367 0 : return False;
368 198 : for (i=9; name[i] && i < len; i++) {
369 138 : if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
370 0 : return False;
371 : }
372 : }
373 : }
374 :
375 : /* check lead characters */
376 880 : for (i=0;i<mangle_prefix;i++) {
377 440 : if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
378 0 : return False;
379 : }
380 : }
381 :
382 : /* check rest of hash */
383 440 : if (! FLAG_CHECK(name[7], FLAG_BASECHAR)) {
384 0 : return False;
385 : }
386 2640 : for (i=mangle_prefix;i<6;i++) {
387 2200 : if (! FLAG_CHECK(name[i], FLAG_BASECHAR)) {
388 0 : return False;
389 : }
390 : }
391 :
392 440 : M_DEBUG(10,("is_mangled_component %s (len %lu) -> yes\n", name, (unsigned long)len));
393 :
394 440 : 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 543468 : static bool is_mangled(const char *name, const struct share_params *parm)
411 : {
412 1759 : const char *p;
413 1759 : const char *s;
414 :
415 543468 : M_DEBUG(10,("is_mangled %s ?\n", name));
416 :
417 543468 : for (s=name; (p=strchr(s, '/')); s=p+1) {
418 0 : if (is_mangled_component(s, PTR_DIFF(p, s))) {
419 0 : return True;
420 : }
421 : }
422 :
423 : /* and the last part ... */
424 543468 : 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 540695 : static bool is_8_3(const char *name, bool check_case, bool allow_wildcards, const struct share_params *p)
441 : {
442 1275 : int len, i;
443 1275 : char *dot_p;
444 :
445 : /* as a special case, the names '.' and '..' are allowable 8.3 names */
446 540695 : if (ISDOT(name) || (ISDOTDOT(name))) {
447 28066 : return true;
448 : }
449 :
450 : /* the simplest test is on the overall length of the
451 : filename. Note that we deliberately use the ascii string
452 : length (not the multi-byte one) as it is faster, and gives us
453 : the result we need in this case. Using strlen_m would not
454 : only be slower, it would be incorrect */
455 512537 : len = strlen(name);
456 512537 : if (len > 12)
457 96400 : return False;
458 :
459 : /* find the '.'. Note that once again we use the non-multibyte
460 : function */
461 415639 : dot_p = strchr(name, '.');
462 :
463 415639 : if (!dot_p) {
464 : /* if the name doesn't contain a '.' then its length
465 : must be less than 8 */
466 322410 : if (len > 8) {
467 15926 : return False;
468 : }
469 : } else {
470 524 : int prefix_len, suffix_len;
471 :
472 : /* if it does contain a dot then the prefix must be <=
473 : 8 and the suffix <= 3 in length */
474 93229 : prefix_len = PTR_DIFF(dot_p, name);
475 93229 : suffix_len = len - (prefix_len+1);
476 :
477 93229 : if (prefix_len > 8 || suffix_len > 3 || suffix_len == 0) {
478 4571 : return False;
479 : }
480 :
481 : /* a 8.3 name cannot contain more than 1 '.' */
482 88361 : if (strchr(dot_p+1, '.')) {
483 4 : return False;
484 : }
485 : }
486 :
487 : /* the length are all OK. Now check to see if the characters themselves are OK */
488 3022566 : for (i=0; name[i]; i++) {
489 2636019 : if (FLAG_CHECK(name[i], FLAG_ILLEGAL)) {
490 7039 : return false;
491 : }
492 : /* note that we may allow wildcard petterns! */
493 2628902 : if (!allow_wildcards && FLAG_CHECK(name[i], FLAG_WILDCARD)) {
494 0 : return false;
495 : }
496 2628902 : if (((unsigned char)name[i]) > 0x7e) {
497 140 : return false;
498 : }
499 2628762 : if (strchr(force_shortname_chars, name[i])) {
500 1006 : return false;
501 : }
502 : }
503 :
504 : /* it is a good 8.3 name */
505 386268 : return True;
506 : }
507 :
508 :
509 : /*
510 : reset the mangling cache on a smb.conf reload. This only really makes sense for
511 : mangling backends that have parameters in smb.conf, and as this backend doesn't
512 : this is a NULL operation
513 : */
514 1522 : static void mangle_reset(void)
515 : {
516 : /* noop */
517 1522 : }
518 :
519 :
520 : /*
521 : try to find a 8.3 name in the cache, and if found then
522 : replace the string with the original long name.
523 : */
524 218 : static bool lookup_name_from_8_3(TALLOC_CTX *ctx,
525 : const char *name,
526 : char **pp_out, /* talloced on the given context. */
527 : const struct share_params *p)
528 : {
529 0 : unsigned int hash, multiplier;
530 0 : unsigned int i;
531 0 : char *prefix;
532 0 : char extension[4];
533 :
534 218 : *pp_out = NULL;
535 :
536 : /* make sure that this is a mangled name from this cache */
537 218 : if (!is_mangled(name, p)) {
538 0 : M_DEBUG(10,("lookup_name_from_8_3: %s -> not mangled\n", name));
539 0 : return False;
540 : }
541 :
542 : /* we need to extract the hash from the 8.3 name */
543 218 : hash = base_reverse[(unsigned char)name[7]];
544 1308 : for (multiplier=36, i=5;i>=mangle_prefix;i--) {
545 1090 : unsigned int v = base_reverse[(unsigned char)name[i]];
546 1090 : hash += multiplier * v;
547 1090 : multiplier *= 36;
548 : }
549 :
550 : /* now look in the prefix cache for that hash */
551 218 : prefix = cache_lookup(ctx, hash);
552 218 : if (!prefix) {
553 32 : M_DEBUG(10,("lookup_name_from_8_3: %s -> %08X -> not found\n",
554 : name, hash));
555 32 : return False;
556 : }
557 :
558 : /* we found it - construct the full name */
559 186 : if (name[8] == '.') {
560 30 : strncpy(extension, name+9, 3);
561 30 : extension[3] = 0;
562 : } else {
563 156 : extension[0] = 0;
564 : }
565 :
566 186 : if (extension[0]) {
567 30 : M_DEBUG(10,("lookup_name_from_8_3: %s -> %s.%s\n",
568 : name, prefix, extension));
569 30 : *pp_out = talloc_asprintf(ctx, "%s.%s", prefix, extension);
570 : } else {
571 156 : M_DEBUG(10,("lookup_name_from_8_3: %s -> %s\n", name, prefix));
572 156 : *pp_out = talloc_strdup(ctx, prefix);
573 : }
574 :
575 186 : TALLOC_FREE(prefix);
576 :
577 186 : if (!*pp_out) {
578 0 : M_DEBUG(0,("talloc_fail\n"));
579 0 : return False;
580 : }
581 :
582 186 : return True;
583 : }
584 :
585 : /*
586 : look for a DOS reserved name
587 : */
588 959136 : static bool is_reserved_name(const char *name)
589 : {
590 959136 : if (FLAG_CHECK(name[0], FLAG_POSSIBLE1) &&
591 19526 : FLAG_CHECK(name[1], FLAG_POSSIBLE2) &&
592 7203 : FLAG_CHECK(name[2], FLAG_POSSIBLE3) &&
593 3797 : FLAG_CHECK(name[3], FLAG_POSSIBLE4)) {
594 : /* a likely match, scan the lot */
595 : int i;
596 18814 : for (i=0; reserved_names[i]; i++) {
597 17996 : int len = strlen(reserved_names[i]);
598 : /* note that we match on COM1 as well as COM1.foo */
599 17996 : if (strnequal(name, reserved_names[i], len) &&
600 0 : (name[len] == '.' || name[len] == 0)) {
601 0 : return True;
602 : }
603 : }
604 : }
605 :
606 958643 : return False;
607 : }
608 :
609 : /*
610 : See if a filename is a legal long filename.
611 : A filename ending in a '.' is not legal unless it's "." or "..". JRA.
612 : A filename ending in ' ' is not legal either. See bug id #2769.
613 : */
614 :
615 959136 : static bool is_legal_name(const char *name)
616 : {
617 959136 : const char *dot_pos = NULL;
618 959136 : bool alldots = True;
619 959136 : size_t numdots = 0;
620 :
621 11620899 : while (*name) {
622 10669080 : if (((unsigned int)name[0]) > 128 && (name[1] != 0)) {
623 : /* Possible start of mb character. */
624 486 : size_t size = 0;
625 486 : (void)next_codepoint(name, &size);
626 : /*
627 : * Note that we're only looking for multibyte
628 : * encoding here. No encoding with a length > 1
629 : * contains invalid characters.
630 : */
631 486 : if (size > 1) {
632 : /* Was a mb string. */
633 46 : name += size;
634 46 : continue;
635 : }
636 : }
637 :
638 10669034 : if (FLAG_CHECK(name[0], FLAG_ILLEGAL)) {
639 7239 : return False;
640 : }
641 10661717 : if (name[0] == '.') {
642 737382 : dot_pos = name;
643 737382 : numdots++;
644 : } else {
645 9921511 : alldots = False;
646 : }
647 10661717 : if ((name[0] == ' ') && (name[1] == '\0')) {
648 : /* Can't end in ' ' */
649 0 : return False;
650 : }
651 10661717 : name++;
652 : }
653 :
654 951819 : if (dot_pos) {
655 718866 : if (alldots && (numdots == 1 || numdots == 2))
656 36414 : return True; /* . or .. is a valid name */
657 :
658 : /* A valid long name cannot end in '.' */
659 682274 : if (dot_pos[1] == '\0')
660 5 : return False;
661 : }
662 914985 : return True;
663 : }
664 :
665 905598 : static bool must_mangle(const char *name,
666 : const struct share_params *p)
667 : {
668 905598 : if (is_reserved_name(name)) {
669 0 : return True;
670 : }
671 905598 : return !is_legal_name(name);
672 : }
673 :
674 : /*
675 : the main forward mapping function, which converts a long filename to
676 : a 8.3 name
677 :
678 : if cache83 is not set then we don't cache the result
679 :
680 : */
681 53538 : static bool hash2_name_to_8_3(const char *name,
682 : char new_name[13],
683 : bool cache83,
684 : int default_case,
685 : const struct share_params *p)
686 : {
687 178 : char *dot_p;
688 178 : char lead_chars[7];
689 178 : char extension[4];
690 178 : unsigned int extension_length, i;
691 178 : unsigned int prefix_len;
692 178 : unsigned int hash, v;
693 :
694 : /* reserved names are handled specially */
695 53538 : if (!is_reserved_name(name)) {
696 : /* if the name is already a valid 8.3 name then we don't need to
697 : * change anything */
698 53538 : if (is_legal_name(name) && is_8_3(name, False, False, p)) {
699 1970 : strlcpy(new_name, name, 13);
700 1970 : return True;
701 : }
702 : }
703 :
704 : /* find the '.' if any */
705 51568 : dot_p = strrchr(name, '.');
706 :
707 51568 : if (dot_p) {
708 : /* if the extension contains any illegal characters or
709 : is too long or zero length then we treat it as part
710 : of the prefix */
711 110700 : for (i=0; i<4 && dot_p[i+1]; i++) {
712 86246 : if (! FLAG_CHECK(dot_p[i+1], FLAG_ASCII)) {
713 450 : dot_p = NULL;
714 450 : break;
715 : }
716 : }
717 24904 : if (i == 0 || i == 4) {
718 13561 : dot_p = NULL;
719 : }
720 : }
721 :
722 : /* the leading characters in the mangled name is taken from
723 : the first characters of the name, if they are ascii otherwise
724 : '_' is used
725 : */
726 103136 : for (i=0;i<mangle_prefix && name[i];i++) {
727 51568 : lead_chars[i] = name[i];
728 51568 : if (! FLAG_CHECK(lead_chars[i], FLAG_ASCII)) {
729 7604 : lead_chars[i] = '_';
730 : }
731 51568 : lead_chars[i] = toupper_m(lead_chars[i]);
732 : }
733 51568 : for (;i<mangle_prefix;i++) {
734 0 : lead_chars[i] = '_';
735 : }
736 :
737 : /* the prefix is anything up to the first dot */
738 51568 : if (dot_p) {
739 11343 : prefix_len = PTR_DIFF(dot_p, name);
740 : } else {
741 40225 : prefix_len = strlen(name);
742 : }
743 :
744 : /* the extension of the mangled name is taken from the first 3
745 : ascii chars after the dot */
746 51568 : extension_length = 0;
747 51568 : if (dot_p) {
748 44715 : for (i=1; extension_length < 3 && dot_p[i]; i++) {
749 33372 : char c = dot_p[i];
750 33372 : if (FLAG_CHECK(c, FLAG_ASCII)) {
751 33372 : extension[extension_length++] =
752 33372 : toupper_m(c);
753 : }
754 : }
755 : }
756 :
757 : /* find the hash for this prefix */
758 51568 : v = hash = mangle_hash(name, prefix_len);
759 :
760 : /* now form the mangled name. */
761 103314 : for (i=0;i<mangle_prefix;i++) {
762 51568 : new_name[i] = lead_chars[i];
763 : }
764 51568 : new_name[7] = base_forward(v % 36);
765 51568 : new_name[6] = '~';
766 309408 : for (i=5; i>=mangle_prefix; i--) {
767 257840 : v = v / 36;
768 257840 : new_name[i] = base_forward(v % 36);
769 : }
770 :
771 : /* add the extension */
772 51568 : if (extension_length) {
773 11343 : new_name[8] = '.';
774 11343 : memcpy(&new_name[9], extension, extension_length);
775 11343 : new_name[9+extension_length] = 0;
776 : } else {
777 40225 : new_name[8] = 0;
778 : }
779 :
780 51568 : if (cache83) {
781 : /* put it in the cache */
782 50629 : cache_insert(name, prefix_len, hash);
783 : }
784 :
785 51568 : M_DEBUG(10,("hash2_name_to_8_3: %s -> %08X -> %s (cache=%d)\n",
786 : name, hash, new_name, cache83));
787 :
788 51390 : return True;
789 : }
790 :
791 : /*
792 : the following provides the abstraction layer to make it easier
793 : to drop in an alternative mangling implementation */
794 : static const struct mangle_fns mangle_hash2_fns = {
795 : mangle_reset,
796 : is_mangled,
797 : must_mangle,
798 : is_8_3,
799 : lookup_name_from_8_3,
800 : hash2_name_to_8_3
801 : };
802 :
803 : /* return the methods for this mangling implementation */
804 163 : const struct mangle_fns *mangle_hash2_init(void)
805 : {
806 : /* the mangle prefix can only be in the mange 1 to 6 */
807 163 : mangle_prefix = lp_mangle_prefix();
808 163 : if (mangle_prefix > 6) {
809 0 : mangle_prefix = 6;
810 : }
811 163 : if (mangle_prefix < 1) {
812 0 : mangle_prefix = 1;
813 : }
814 :
815 : #if DYNAMIC_MANGLE_TABLES
816 : init_tables();
817 : #endif
818 163 : mangle_reset();
819 :
820 163 : return &mangle_hash2_fns;
821 : }
822 :
823 478 : static void posix_mangle_reset(void)
824 478 : {;}
825 :
826 646 : static bool posix_is_mangled(const char *s, const struct share_params *p)
827 : {
828 646 : return False;
829 : }
830 :
831 3325 : static bool posix_must_mangle(const char *s, const struct share_params *p)
832 : {
833 3325 : return False;
834 : }
835 :
836 3829 : static bool posix_is_8_3(const char *fname,
837 : bool check_case,
838 : bool allow_wildcards,
839 : const struct share_params *p)
840 : {
841 3829 : return False;
842 : }
843 :
844 0 : static bool posix_lookup_name_from_8_3(TALLOC_CTX *ctx,
845 : const char *in,
846 : char **out, /* talloced on the given context. */
847 : const struct share_params *p)
848 : {
849 0 : return False;
850 : }
851 :
852 3191 : static bool posix_name_to_8_3(const char *in,
853 : char out[13],
854 : bool cache83,
855 : int default_case,
856 : const struct share_params *p)
857 : {
858 3191 : memset(out, '\0', 13);
859 3191 : return True;
860 : }
861 :
862 : /* POSIX paths backend - no mangle. */
863 : static const struct mangle_fns posix_mangle_fns = {
864 : posix_mangle_reset,
865 : posix_is_mangled,
866 : posix_must_mangle,
867 : posix_is_8_3,
868 : posix_lookup_name_from_8_3,
869 : posix_name_to_8_3
870 : };
871 :
872 478 : const struct mangle_fns *posix_mangle_init(void)
873 : {
874 478 : return &posix_mangle_fns;
875 : }
|