diff options
Diffstat (limited to 'source/smbd/mangle.c')
-rw-r--r-- | source/smbd/mangle.c | 630 |
1 files changed, 72 insertions, 558 deletions
diff --git a/source/smbd/mangle.c b/source/smbd/mangle.c index 8f1490c528d..392e48afc19 100644 --- a/source/smbd/mangle.c +++ b/source/smbd/mangle.c @@ -1,8 +1,7 @@ /* - Unix SMB/Netbios implementation. - Version 1.9. - Name mangling - Copyright (C) Andrew Tridgell 1992-1995 + Unix SMB/CIFS implementation. + Name mangling interface + Copyright (C) Andrew Tridgell 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,591 +19,106 @@ */ #include "includes.h" -#include "loadparm.h" - -extern int DEBUGLEVEL; -extern int case_default; -extern BOOL case_mangle; - -/**************************************************************************** -provide a checksum on a string -****************************************************************************/ -int str_checksum(char *s) -{ - int res = 0; - int c; - int i=0; - while (*s) - { - c = *s; - res ^= (c << (i % 15)) ^ (c >> (15-(i%15))); - s++; i++; - } - return(res); -} - -/**************************************************************************** -return True if a name is a special msdos reserved name -****************************************************************************/ -static BOOL is_reserved_msdos(char *fname) -{ - char upperFname[13]; - char *p; - - StrnCpy (upperFname, fname, 12); - - /* lpt1.txt and con.txt etc are also illegal */ - p=strchr(upperFname,'.'); - if (p) - *p='\0'; - strupper (upperFname); - if ((strcmp(upperFname,"CLOCK$") == 0) || - (strcmp(upperFname,"CON") == 0) || - (strcmp(upperFname,"AUX") == 0) || - (strcmp(upperFname,"COM1") == 0) || - (strcmp(upperFname,"COM2") == 0) || - (strcmp(upperFname,"COM3") == 0) || - (strcmp(upperFname,"COM4") == 0) || - (strcmp(upperFname,"LPT1") == 0) || - (strcmp(upperFname,"LPT2") == 0) || - (strcmp(upperFname,"LPT3") == 0) || - (strcmp(upperFname,"NUL") == 0) || - (strcmp(upperFname,"PRN") == 0)) - return (True) ; - - return (False); -} - - - -/**************************************************************************** -return True if a name is in 8.3 dos format -****************************************************************************/ -BOOL is_8_3(char *fname) -{ - int len; - char *dot_pos; - char *slash_pos = strrchr(fname,'/'); - int l; - - if (slash_pos) fname = slash_pos+1; - len = strlen(fname); - - dot_pos = strchr(fname,'.'); - - DEBUG(5,("checking %s for 8.3\n",fname)); - - if (case_mangle) - switch (case_default) - { - case CASE_LOWER: - if (strhasupper(fname)) return(False); - break; - case CASE_UPPER: - if (strhaslower(fname)) return(False); - break; - } - - /* can't be longer than 12 chars */ - if (len == 0 || len > 12) - return(False); - - /* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */ - if (is_reserved_msdos(fname)) - return(False); - - /* can't contain invalid dos chars */ - /* Windows use the ANSI charset. - But filenames are translated in the PC charset. - This Translation may be more or less relaxed depending - the Windows application. */ - - /* %%% A nice improvment to name mangling would be to translate - filename to ANSI charset on the smb server host */ - - { - char *p = fname; -#ifdef KANJI - dot_pos = 0; - while (*p) - { - if (is_shift_jis (*p)) { - p += 2; - } else if (is_kana (*p)) { - p ++; - } else { - if (*p == '.' && !dot_pos) - dot_pos = (char *) p; - if (!isdoschar(*p)) - return(False); - p++; - } - } -#else - while (*p) - { - if (!isdoschar(*p)) - return(False); - p++; - } -#endif /* KANJI */ - } - - /* no dot and less than 9 means OK */ - if (!dot_pos) - return(len <= 8); - - l = PTR_DIFF(dot_pos,fname); - - /* base must be at least 1 char except special cases . and .. */ - if (l == 0) - return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0); - - /* base can't be greater than 8 */ - if (l > 8) - return(False); - - if (lp_strip_dot() && - len - l == 1 && - !strchr(dot_pos+1,'.')) - { - *dot_pos = 0; - return(True); - } - - /* extension must be between 1 and 3 */ - if ( (len - l < 2 ) || (len - l > 4) ) - return(False); - - /* extension can't have a dot */ - if (strchr(dot_pos+1,'.')) - return(False); - - /* must be in 8.3 format */ - return(True); -} +static struct mangle_fns *mangle_fns; +/* this allows us to add more mangling backends */ +static struct { + char *name; + struct mangle_fns *(*init_fn)(void); +} mangle_backends[] = { + { "hash", mangle_hash_init }, + { "hash2", mangle_hash2_init }, + /*{ "tdb", mangle_tdb_init }, */ + { NULL, NULL } +}; /* -keep a stack of name mangling results - just -so file moves and copies have a chance of working + initialise the mangling subsystem */ -fstring *mangled_stack = NULL; -int mangled_stack_size = 0; -int mangled_stack_len = 0; - -/**************************************************************************** -create the mangled stack -****************************************************************************/ -void create_mangled_stack(int size) -{ - if (mangled_stack) - { - free(mangled_stack); - mangled_stack_size = 0; - mangled_stack_len = 0; - } - if (size > 0) - mangled_stack = (fstring *)malloc(sizeof(fstring)*size); - if (mangled_stack) mangled_stack_size = size; -} - -/**************************************************************************** -push a mangled name onto the stack -****************************************************************************/ -static void push_mangled_name(char *s) +static void mangle_init(void) { - int i; - char *p; - - if (!mangled_stack) - return; + int i; + char *method; - for (i=0;i<mangled_stack_len;i++) - if (strcmp(s,mangled_stack[i]) == 0) - { - array_promote(mangled_stack[0],sizeof(fstring),i); - return; - } + if (mangle_fns) + return; - memmove(mangled_stack[1],mangled_stack[0], - sizeof(fstring)*MIN(mangled_stack_len,mangled_stack_size-1)); - strcpy(mangled_stack[0],s); - p = strrchr(mangled_stack[0],'.'); - if (p && (!strhasupper(p+1)) && (strlen(p+1) < 4)) - *p = 0; - mangled_stack_len = MIN(mangled_stack_size,mangled_stack_len+1); -} - -/**************************************************************************** -check for a name on the mangled name stack -****************************************************************************/ -BOOL check_mangled_stack(char *s) -{ - int i; - pstring tmpname; - char extension[5]; - char *p = strrchr(s,'.'); - BOOL check_extension = False; + method = lp_mangling_method(); - extension[0] = 0; - - if (!mangled_stack) return(False); - - if (p) - { - check_extension = True; - StrnCpy(extension,p,4); - strlower(extension); /* XXXXXXX */ - } - - for (i=0;i<mangled_stack_len;i++) - { - strcpy(tmpname,mangled_stack[i]); - mangle_name_83(tmpname); - if (strequal(tmpname,s)) - { - strcpy(s,mangled_stack[i]); - break; + /* find the first mangling method that manages to initialise and + matches the "mangling method" parameter */ + for (i=0; mangle_backends[i].name && !mangle_fns; i++) { + if (!method || !*method || strcmp(method, mangle_backends[i].name) == 0) { + mangle_fns = mangle_backends[i].init_fn(); + } } - if (check_extension && !strchr(mangled_stack[i],'.')) - { - strcpy(tmpname,mangled_stack[i]); - strcat(tmpname,extension); - mangle_name_83(tmpname); - if (strequal(tmpname,s)) - { - strcpy(s,mangled_stack[i]); - strcat(s,extension); - break; - } - } - } - - if (i < mangled_stack_len) - { - DEBUG(3,("Found %s on mangled stack as %s\n",s,mangled_stack[i])); - array_promote(mangled_stack[0],sizeof(fstring),i); - return(True); - } - return(False); -} - -static char *map_filename(char *s, /* This is null terminated */ - char *pattern, /* This isn't. */ - int len) /* This is the length of pattern. */ -{ - static pstring matching_bit; /* The bit of the string which matches */ - /* a * in pattern if indeed there is a * */ - char *sp; /* Pointer into s. */ - char *pp; /* Pointer into p. */ - char *match_start; /* Where the matching bit starts. */ - pstring pat; - - StrnCpy(pat, pattern, len); /* Get pattern into a proper string! */ - strcpy(matching_bit,""); /* Match but no star gets this. */ - pp = pat; /* Initialise the pointers. */ - sp = s; - if ((len == 1) && (*pattern == '*')) { - return NULL; /* Impossible, too ambiguous for */ - /* words! */ - } - - while ((*sp) /* Not the end of the string. */ - && (*pp) /* Not the end of the pattern. */ - && (*sp == *pp) /* The two match. */ - && (*pp != '*')) { /* No wildcard. */ - sp++; /* Keep looking. */ - pp++; - } - if (!*sp && !*pp) /* End of pattern. */ - return matching_bit; /* Simple match. Return empty string. */ - if (*pp == '*') { - pp++; /* Always interrested in the chacter */ - /* after the '*' */ - if (!*pp) { /* It is at the end of the pattern. */ - StrnCpy(matching_bit, s, sp-s); - return matching_bit; - } else { - /* The next character in pattern must match a character further */ - /* along s than sp so look for that character. */ - match_start = sp; - while ((*sp) /* Not the end of s. */ - && (*sp != *pp)) /* Not the same */ - sp++; /* Keep looking. */ - if (!*sp) { /* Got to the end without a match. */ - return NULL; - } else { /* Still hope for a match. */ - /* Now sp should point to a matching character. */ - StrnCpy(matching_bit, match_start, sp-match_start); - /* Back to needing a stright match again. */ - while ((*sp) /* Not the end of the string. */ - && (*pp) /* Not the end of the pattern. */ - && (*sp == *pp)) { /* The two match. */ - sp++; /* Keep looking. */ - pp++; - } - if (!*sp && !*pp) /* Both at end so it matched */ - return matching_bit; - else - return NULL; - } - } - } - return NULL; /* No match. */ + if (!mangle_fns) { + DEBUG(0,("Failed to initialise mangling system '%s'\n", method)); + exit_server("mangling init failed"); + } } -/* this is the magic char used for mangling */ -char magic_char = '~'; - - -/**************************************************************************** -determine whther is name could be a mangled name -****************************************************************************/ -BOOL is_mangled(char *s) +/* + reset the cache. This is called when smb.conf has been reloaded +*/ +void mangle_reset_cache(void) { - char *m = strchr(s,magic_char); - if (!m) return(False); + mangle_init(); - /* we use two base 36 chars efore the extension */ - if (m[1] == '.' || m[1] == 0 || - m[2] == '.' || m[2] == 0 || - (m[3] != '.' && m[3] != 0)) - return(is_mangled(m+1)); - - /* it could be */ - return(True); + mangle_fns->reset(); } - - -/**************************************************************************** -return a base 36 character. v must be from 0 to 35. -****************************************************************************/ -static char base36(int v) +/* + see if a filename has come out of our mangling code +*/ +BOOL mangle_is_mangled(const char *s) { - v = v % 36; - if (v < 10) - return('0'+v); - else /* needed to work around a DEC C compiler bug */ - return('A' + (v-10)); + return mangle_fns->is_mangled(s); } - -static void do_fwd_mangled_map(char *s, char *MangledMap) +/* + see if a filename matches the rules of a 8.3 filename +*/ +BOOL mangle_is_8_3(const char *fname, BOOL check_case) { - /* MangledMap is a series of name pairs in () separated by spaces. - * If s matches the first of the pair then the name given is the - * second of the pair. A * means any number of any character and if - * present in the second of the pair as well as the first the - * matching part of the first string takes the place of the * in the - * second. - * - * I wanted this so that we could have RCS files which can be used - * by UNIX and DOS programs. My mapping string is (RCS rcs) which - * converts the UNIX RCS file subdirectory to lowercase thus - * preventing mangling. - */ - char *start=MangledMap; /* Use this to search for mappings. */ - char *end; /* Used to find the end of strings. */ - char *match_string; - pstring new_string; /* Make up the result here. */ - char *np; /* Points into new_string. */ - - DEBUG(5,("Mangled Mapping '%s' map '%s'\n", s, MangledMap)); - while (*start) { - while ((*start) && (*start != '(')) - start++; - start++; /* Skip the ( */ - if (!*start) - continue; /* Always check for the end. */ - end = start; /* Search for the ' ' or a ')' */ - DEBUG(5,("Start of first in pair '%s'\n", start)); - while ((*end) && !((*end == ' ') || (*end == ')'))) - end++; - if (!*end) { - start = end; - continue; /* Always check for the end. */ - } - DEBUG(5,("End of first in pair '%s'\n", end)); - if ((match_string = map_filename(s, start, end-start))) { - DEBUG(5,("Found a match\n")); - /* Found a match. */ - start = end+1; /* Point to start of what it is to become. */ - DEBUG(5,("Start of second in pair '%s'\n", start)); - end = start; - np = new_string; - while ((*end) /* Not the end of string. */ - && (*end != ')') /* Not the end of the pattern. */ - && (*end != '*')) /* Not a wildcard. */ - *np++ = *end++; - if (!*end) { - start = end; - continue; /* Always check for the end. */ - } - if (*end == '*') { - strcpy(np, match_string); - np += strlen(match_string); - end++; /* Skip the '*' */ - while ((*end) /* Not the end of string. */ - && (*end != ')') /* Not the end of the pattern. */ - && (*end != '*')) /* Not a wildcard. */ - *np++ = *end++; - } - if (!*end) { - start = end; - continue; /* Always check for the end. */ - } - *np++ = '\0'; /* NULL terminate it. */ - DEBUG(5,("End of second in pair '%s'\n", end)); - strcpy(s, new_string); /* Substitute with the new name. */ - DEBUG(5,("s is now '%s'\n", s)); - } - start = end; /* Skip a bit which cannot be wanted */ - /* anymore. */ - start++; - } + return mangle_fns->is_8_3(fname, check_case, False); } -/**************************************************************************** -do the actual mangling to 8.3 format -****************************************************************************/ -void mangle_name_83(char *s) +BOOL mangle_is_8_3_wildcards(const char *fname, BOOL check_case) { - int csum = str_checksum(s); - char *p; - char extension[4]; - char base[9]; - int baselen = 0; - int extlen = 0; - - extension[0]=0; - base[0]=0; - - p = strrchr(s,'.'); - if (p && (strlen(p+1)<4) ) - { - BOOL all_normal = (strisnormal(p+1)); /* XXXXXXXXX */ - if (all_normal && p[1] != 0) - { - *p = 0; - csum = str_checksum(s); - *p = '.'; - } - } - - - strupper(s); - - DEBUG(5,("Mangling name %s to ",s)); - - if (p) - { - if (p == s) - strcpy(extension,"___"); - else - { - *p++ = 0; - while (*p && extlen < 3) - { - if (isdoschar(*p) && *p != '.') - extension[extlen++] = *p; - p++; - } - extension[extlen] = 0; - } - } - - p = s; - - while (*p && baselen < 5) - { - if (isdoschar(*p) && *p != '.') - base[baselen++] = *p; - p++; - } - base[baselen] = 0; - - csum = csum % (36*36); - - sprintf(s,"%s%c%c%c",base,magic_char,base36(csum/36),base36(csum%36)); - - if (*extension) - { - strcat(s,"."); - strcat(s,extension); - } - DEBUG(5,("%s\n",s)); + return mangle_fns->is_8_3(fname, check_case, True); } - - -/******************************************************************* - work out if a name is illegal, even for long names - ******************************************************************/ -static BOOL illegal_name(char *name) +/* + try to reverse map a 8.3 name to the original filename. This doesn't have to + always succeed, as the directory handling code in smbd will scan the directory + looking for a matching name if it doesn't. It should succeed most of the time + or there will be a huge performance penalty +*/ +BOOL mangle_check_cache(char *s) { - static unsigned char illegal[256]; - static BOOL initialised=False; - unsigned char *s; - - if (!initialised) { - char *ill = "*\\/?<>|\":{}"; - initialised = True; - - bzero((char *)illegal,256); - for (s = (unsigned char *)ill; *s; s++) - illegal[*s] = True; - } - -#ifdef KANJI - for (s = (unsigned char *)name; *s;) { - if (is_shift_jis (*s)) { - s += 2; - } else if (illegal[*s]) { - return(True); - } else { - s++; - } - } -#else - for (s = (unsigned char *)name;*s;s++) - if (illegal[*s]) return(True); -#endif - - - return(False); + return mangle_fns->check_cache(s); } +/* + map a long filename to a 8.3 name. + */ -/**************************************************************************** -convert a filename to DOS format. return True if successful. -****************************************************************************/ -BOOL name_map_mangle(char *OutName,BOOL need83,int snum) +void mangle_map(char *OutName, BOOL need83, BOOL cache83, int snum) { -#ifdef MANGLE_LONG_FILENAMES - if (!need83 && illegal_name(OutName)) need83 = True; -#endif - - /* apply any name mappings */ - { - char *map = lp_mangled_map(snum); - if (map && *map) - do_fwd_mangled_map(OutName,map); - } - - /* check if it's already in 8.3 format */ - if (need83 && !is_8_3(OutName)) { - if (!lp_manglednames(snum)) return(False); + /* name mangling can be disabled for speed, in which case + we just truncate the string */ + if (!lp_manglednames(snum)) { + if (need83) { + string_truncate(OutName, 12); + } + return; + } - /* mangle it into 8.3 */ - push_mangled_name(OutName); - mangle_name_83(OutName); - } - - return(True); + /* invoke the inane "mangled map" code */ + mangle_map_filename(OutName, snum); + mangle_fns->name_map(OutName, need83, cache83); } - |