LCOV - code coverage report
Current view: top level - source3/smbd - mangle_hash2.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 210 237 88.6 %
Date: 2024-04-21 15:09:00 Functions: 19 20 95.0 %

          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             : }

Generated by: LCOV version 1.14