int strcmp_wa(const smb_ucs2_t *a, const char *b) { smb_ucs2_t cp = 0; while (*b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) { a++; b++; } return (*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b)); }
static int null_match(const smb_ucs2_t *p) { for (;*p;p++) { if (*p != UCS2_CHAR('*') && *p != UCS2_CHAR('<') && *p != UCS2_CHAR('"') && *p != UCS2_CHAR('>')) return -1; } return 0; }
int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len) { smb_ucs2_t cp = 0; size_t n = 0; while ((n < len) && *b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) { a++; b++; n++; } return (len - n)?(*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b)):0; }
static NTSTATUS mangle_get_prefix(const smb_ucs2_t *ucs2_string, smb_ucs2_t **prefix, smb_ucs2_t **extension, bool allow_wildcards) { size_t ext_len; smb_ucs2_t *p; *extension = 0; *prefix = strdup_w(ucs2_string); if (!*prefix) { return NT_STATUS_NO_MEMORY; } if ((p = strrchr_w(*prefix, UCS2_CHAR('.')))) { ext_len = strlen_w(p+1); if ((ext_len > 0) && (ext_len < 4) && (p != *prefix) && (NT_STATUS_IS_OK(has_valid_83_chars(p+1,allow_wildcards)))) /* check extension */ { *p = 0; *extension = strdup_w(p+1); if (!*extension) { SAFE_FREE(*prefix); return NT_STATUS_NO_MEMORY; } } } return NT_STATUS_OK; }
void pstrcpy_wa(smb_ucs2_t *dest, const char *src) { int i; for (i=0;i<PSTRING_LEN;i++) { dest[i] = UCS2_CHAR(src[i]); if (src[i] == 0) return; } }
/** * Load or generate the case handling tables. * * The case tables are defined in UCS2 and don't depend on any * configured parameters, so they never need to be reloaded. **/ void load_case_tables(void) { static int initialised; int i; if (initialised) return; initialised = 1; upcase_table = map_file(lib_path("upcase.dat"), 0x20000); lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000); /* we would like Samba to limp along even if these tables are not available */ if (!upcase_table) { DEBUG(1,("creating lame upcase table\n")); upcase_table = malloc(0x20000); for (i=0;i<0x10000;i++) { smb_ucs2_t v; SSVAL(&v, 0, i); upcase_table[v] = i; } for (i=0;i<256;i++) { smb_ucs2_t v; SSVAL(&v, 0, UCS2_CHAR(i)); upcase_table[v] = UCS2_CHAR(islower(i)?toupper(i):i); } } if (!lowcase_table) { DEBUG(1,("creating lame lowcase table\n")); lowcase_table = malloc(0x20000); for (i=0;i<0x10000;i++) { smb_ucs2_t v; SSVAL(&v, 0, i); lowcase_table[v] = i; } for (i=0;i<256;i++) { smb_ucs2_t v; SSVAL(&v, 0, UCS2_CHAR(i)); lowcase_table[v] = UCS2_CHAR(isupper(i)?tolower(i):i); } } }
smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p) { while (*s != 0) { int i; for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++) ; if (p[i]) return (smb_ucs2_t *)s; s++; } return NULL; }
static NTSTATUS has_illegal_chars(const smb_ucs2_t *s, bool allow_wildcards) { if (!allow_wildcards && ms_has_wild_w(s)) { return NT_STATUS_UNSUCCESSFUL; } while (*s) { if (*s <= 0x1f) { /* Control characters. */ return NT_STATUS_UNSUCCESSFUL; } switch(*s) { case UCS2_CHAR('\\'): case UCS2_CHAR('/'): case UCS2_CHAR('|'): case UCS2_CHAR(':'): return NT_STATUS_UNSUCCESSFUL; } s++; } return NT_STATUS_OK; }
smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins) { smb_ucs2_t *r; size_t slen, inslen; if (!s || !*s || !ins || !*ins) return NULL; slen = strlen_w(s); inslen = strlen(ins); r = (smb_ucs2_t *)s; while ((r = strchr_w(r, UCS2_CHAR(*ins)))) { if (strncmp_wa(r, ins, inslen) == 0) return r; r++; } return NULL; }
smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p) { smb_ucs2_t cp; while (*(COPY_UCS2_CHAR(&cp,s))) { int i; for (i=0; p[i] && cp != UCS2_CHAR(p[i]); i++) ; if (p[i]) { return (smb_ucs2_t *)s; } s++; } return NULL; }
static NTSTATUS is_8_3_w(const smb_ucs2_t *fname, bool allow_wildcards) { smb_ucs2_t *pref = 0, *ext = 0; size_t plen; NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER; if (strlen_w(fname) > 12) return NT_STATUS_UNSUCCESSFUL; if (strcmp_wa(fname, ".") == 0 || strcmp_wa(fname, "..") == 0) return NT_STATUS_OK; /* Name cannot start with '.' */ if (*fname == UCS2_CHAR('.')) return NT_STATUS_UNSUCCESSFUL; if (!NT_STATUS_IS_OK(is_valid_name(fname, allow_wildcards, True))) goto done; if (!NT_STATUS_IS_OK(mangle_get_prefix(fname, &pref, &ext, allow_wildcards))) goto done; plen = strlen_w(pref); if (strchr_wa(pref, '.')) goto done; if (plen < 1 || plen > 8) goto done; if (ext && (strlen_w(ext) > 3)) goto done; ret = NT_STATUS_OK; done: SAFE_FREE(pref); SAFE_FREE(ext); return ret; }
/* p and n are the pattern and string being matched. The max_n array is an optimisation only. The ldot pointer is NULL if the string does not contain a '.', otherwise it points at the last dot in 'n'. */ static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n, struct max_n *max_n, const smb_ucs2_t *ldot, bool is_case_sensitive) { smb_ucs2_t c; int i; while ((c = *p++)) { switch (c) { /* a '*' matches zero or more characters of any type */ case UCS2_CHAR('*'): if (max_n->predot && max_n->predot <= n) { return null_match(p); } for (i=0; n[i]; i++) { if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) { return 0; } } if (!max_n->predot || max_n->predot > n) max_n->predot = n; return null_match(p); /* a '<' matches zero or more characters of any type, but stops matching at the last '.' in the string. */ case UCS2_CHAR('<'): if (max_n->predot && max_n->predot <= n) { return null_match(p); } if (max_n->postdot && max_n->postdot <= n && n <= ldot) { return -1; } for (i=0; n[i]; i++) { if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) return 0; if (n+i == ldot) { if (ms_fnmatch_core(p, n+i+1, max_n+1, ldot, is_case_sensitive) == 0) return 0; if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n; return -1; } } if (!max_n->predot || max_n->predot > n) max_n->predot = n; return null_match(p); /* a '?' matches any single character */ case UCS2_CHAR('?'): if (! *n) { return -1; } n++; break; /* a '?' matches any single character */ case UCS2_CHAR('>'): if (n[0] == UCS2_CHAR('.')) { if (! n[1] && null_match(p) == 0) { return 0; } break; } if (! *n) return null_match(p); n++; break; case UCS2_CHAR('"'): if (*n == 0 && null_match(p) == 0) { return 0; } if (*n != UCS2_CHAR('.')) return -1; n++; break; default: if (c != *n) { if (is_case_sensitive) { return -1; } if (toupper_w(c) != toupper_w(*n)) { return -1; } } n++; break; } } if (! *n) { return 0; } return -1; }
int tolower_ascii(int c) { smb_ucs2_t uc = tolower_w(UCS2_CHAR(c)); return UCS2_TO_CHAR(uc); }
int strcmp_wa(const smb_ucs2_t *a, const char *b) { while (*b && *a == UCS2_CHAR(*b)) { a++; b++; } return (*a - UCS2_CHAR(*b)); }
int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len) { size_t n = 0; while ((n < len) && *b && *a == UCS2_CHAR(*b)) { a++; b++; n++;} return (len - n)?(*a - UCS2_CHAR(*b)):0; }
static NTSTATUS is_valid_name(const smb_ucs2_t *fname, bool allow_wildcards, bool only_8_3) { smb_ucs2_t *str, *p; size_t num_ucs2_chars; NTSTATUS ret = NT_STATUS_OK; if (!fname || !*fname) return NT_STATUS_INVALID_PARAMETER; /* . and .. are valid names. */ if (strcmp_wa(fname, ".")==0 || strcmp_wa(fname, "..")==0) return NT_STATUS_OK; if (only_8_3) { ret = has_valid_83_chars(fname, allow_wildcards); if (!NT_STATUS_IS_OK(ret)) return ret; } ret = has_illegal_chars(fname, allow_wildcards); if (!NT_STATUS_IS_OK(ret)) return ret; /* Name can't end in '.' or ' ' */ num_ucs2_chars = strlen_w(fname); if (fname[num_ucs2_chars-1] == UCS2_CHAR('.') || fname[num_ucs2_chars-1] == UCS2_CHAR(' ')) { return NT_STATUS_UNSUCCESSFUL; } str = strdup_w(fname); /* Truncate copy after the first dot. */ p = strchr_w(str, UCS2_CHAR('.')); if (p) { *p = 0; } strupper_w(str); p = &str[1]; switch(str[0]) { case UCS2_CHAR('A'): if(strcmp_wa(p, "UX") == 0) ret = NT_STATUS_UNSUCCESSFUL; break; case UCS2_CHAR('C'): if((strcmp_wa(p, "LOCK$") == 0) || (strcmp_wa(p, "ON") == 0) || (strcmp_wa(p, "OM1") == 0) || (strcmp_wa(p, "OM2") == 0) || (strcmp_wa(p, "OM3") == 0) || (strcmp_wa(p, "OM4") == 0) ) ret = NT_STATUS_UNSUCCESSFUL; break; case UCS2_CHAR('L'): if((strcmp_wa(p, "PT1") == 0) || (strcmp_wa(p, "PT2") == 0) || (strcmp_wa(p, "PT3") == 0) ) ret = NT_STATUS_UNSUCCESSFUL; break; case UCS2_CHAR('N'): if(strcmp_wa(p, "UL") == 0) ret = NT_STATUS_UNSUCCESSFUL; break; case UCS2_CHAR('P'): if(strcmp_wa(p, "RN") == 0) ret = NT_STATUS_UNSUCCESSFUL; break; default: break; } SAFE_FREE(str); return ret; }
void load_case_tables(void) { static int initialised; char *old_locale = NULL, *saved_locale = NULL; int i; if (initialised) { return; } initialised = 1; upcase_table = map_file(lib_path("upcase.dat"), 0x20000); upcase_table_use_unmap = ( upcase_table != NULL ); lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000); lowcase_table_use_unmap = ( lowcase_table != NULL ); #ifdef HAVE_SETLOCALE /* Get the name of the current locale. */ old_locale = setlocale(LC_ALL, NULL); if (old_locale) { /* Save it as it is in static storage. */ saved_locale = SMB_STRDUP(old_locale); } /* We set back the locale to C to get ASCII-compatible toupper/lower functions. */ setlocale(LC_ALL, "C"); #endif /* we would like Samba to limp along even if these tables are not available */ if (!upcase_table) { DEBUG(1,("creating lame upcase table\n")); upcase_table = SMB_MALLOC(0x20000); for (i=0;i<0x10000;i++) { smb_ucs2_t v; SSVAL(&v, 0, i); upcase_table[v] = i; } for (i=0;i<256;i++) { smb_ucs2_t v; SSVAL(&v, 0, UCS2_CHAR(i)); upcase_table[v] = UCS2_CHAR(islower(i)?toupper(i):i); } } if (!lowcase_table) { DEBUG(1,("creating lame lowcase table\n")); lowcase_table = SMB_MALLOC(0x20000); for (i=0;i<0x10000;i++) { smb_ucs2_t v; SSVAL(&v, 0, i); lowcase_table[v] = i; } for (i=0;i<256;i++) { smb_ucs2_t v; SSVAL(&v, 0, UCS2_CHAR(i)); lowcase_table[v] = UCS2_CHAR(isupper(i)?tolower(i):i); } } #ifdef HAVE_SETLOCALE /* Restore the old locale. */ if (saved_locale) { setlocale (LC_ALL, saved_locale); SAFE_FREE(saved_locale); } #endif }
smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c) { return strchr_w(s, UCS2_CHAR(c)); }
int islower_ascii(int c) { return islower_w(UCS2_CHAR(c)); }
int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern, bool is_case_sensitive) { smb_ucs2_t *p = NULL; smb_ucs2_t *s = NULL; int ret, count, i; struct max_n *max_n = NULL; struct max_n *max_n_free = NULL; struct max_n one_max_n; size_t converted_size; if (ISDOTDOT(string)) { string = "."; } if (strpbrk(pattern, "<>*?\"") == NULL) { /* this is not just an optmisation - it is essential for LANMAN1 correctness */ if (is_case_sensitive) { return strcmp(pattern, string); } else { return StrCaseCmp(pattern, string); } } if (!push_ucs2_talloc(talloc_tos(), &p, pattern, &converted_size)) { return -1; } if (!push_ucs2_talloc(talloc_tos(), &s, string, &converted_size)) { TALLOC_FREE(p); return -1; } if (translate_pattern) { /* for older negotiated protocols it is possible to translate the pattern to produce a "new style" pattern that exactly matches w2k behaviour */ for (i=0;p[i];i++) { if (p[i] == UCS2_CHAR('?')) { p[i] = UCS2_CHAR('>'); } else if (p[i] == UCS2_CHAR('.') && (p[i+1] == UCS2_CHAR('?') || p[i+1] == UCS2_CHAR('*') || p[i+1] == 0)) { p[i] = UCS2_CHAR('"'); } else if (p[i] == UCS2_CHAR('*') && p[i+1] == UCS2_CHAR('.')) { p[i] = UCS2_CHAR('<'); } } } for (count=i=0;p[i];i++) { if (p[i] == UCS2_CHAR('*') || p[i] == UCS2_CHAR('<')) count++; } if (count != 0) { if (count == 1) { /* * We're doing this a LOT, so save the effort to allocate */ ZERO_STRUCT(one_max_n); max_n = &one_max_n; } else { max_n = SMB_CALLOC_ARRAY(struct max_n, count); if (!max_n) { TALLOC_FREE(p); TALLOC_FREE(s); return -1; } max_n_free = max_n; } } ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive); SAFE_FREE(max_n_free); TALLOC_FREE(p); TALLOC_FREE(s); return ret; }