LCOV - code coverage report
Current view: top level - source3/smbd - mangle_hash2.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 194 218 89.0 %
Date: 2021-09-23 10:06:22 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 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             : }

Generated by: LCOV version 1.13