Small bit of paranioa. Ensure that if the incoming name to
[samba.git] / source3 / smbd / filename.c
index 9112828092865274d603103223789c2fd0839efe..7cbb3392cb7423b5916e0256c28d1a61df72f42a 100644 (file)
@@ -28,12 +28,13 @@ extern BOOL short_case_preserve;
 extern fstring remote_machine;
 extern BOOL use_mangled_map;
 
+static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache);
+
 /****************************************************************************
  Check if two filenames are equal.
  This needs to be careful about whether we are case sensitive.
 ****************************************************************************/
-
-BOOL fname_equal(char *name1, char *name2)
+static BOOL fname_equal(char *name1, char *name2)
 {
   int l1 = strlen(name1);
   int l2 = strlen(name2);
@@ -68,8 +69,7 @@ BOOL fname_equal(char *name1, char *name2)
 /****************************************************************************
  Mangle the 2nd name and check if it is then equal to the first name.
 ****************************************************************************/
-
-BOOL mangled_equal(char *name1, char *name2)
+static BOOL mangled_equal(char *name1, char *name2)
 {
   pstring tmpname;
 
@@ -77,7 +77,7 @@ BOOL mangled_equal(char *name1, char *name2)
     return(False);
 
   pstrcpy(tmpname,name2);
-  mangle_name_83(tmpname,sizeof(tmpname));
+  mangle_name_83(tmpname);
 
   return(strequal(name1,tmpname));
 }
@@ -114,27 +114,18 @@ typedef struct {
 
 static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0};
 
-/****************************************************************************
- Compare two names in the stat cache - to check if we already have such an
- entry.
-*****************************************************************************/
-
-static BOOL stat_name_equal( char *s1, char *s2)
-{
-  return (case_sensitive ? (strcmp( s1, s2) == 0) : (StrCaseCmp(s1, s2) == 0));
-}
-
 /****************************************************************************
  Compare a pathname to a name in the stat cache - of a given length.
  Note - this code always checks that the next character in the pathname
  is either a '/' character, or a '\0' character - to ensure we only
- match *full* pathname components.
+ match *full* pathname components. Note we don't need to handle case
+ here, if we're case insensitive the stat cache orig names are all upper
+ case.
 *****************************************************************************/
 
 static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
 {
-  BOOL matched = (case_sensitive ? (strncmp( stat_name, orig_name, len) == 0) :
-                           (StrnCaseCmp(stat_name, orig_name, len) == 0));
+  BOOL matched = (memcmp( stat_name, orig_name, len) == 0);
   if(orig_name[len] != '/' && orig_name[len] != '\0')
     return False;
 
@@ -150,12 +141,17 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
   stat_cache_entry *scp;
   pstring orig_name;
   pstring translated_path;
-  int namelen = strlen(orig_translated_path);
+  int namelen;
+
+  if (!lp_stat_cache()) return;
+
+  namelen = strlen(orig_translated_path);
 
   /*
    * Don't cache trivial valid directory entries.
    */
-  if(strequal(full_orig_name, ".") || strequal(full_orig_name, ".."))
+  if((*full_orig_name == '\0') || (strcmp(full_orig_name, ".") == 0) ||
+     (strcmp(full_orig_name, "..") == 0))
     return;
 
   /*
@@ -185,6 +181,8 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
    */
 
   StrnCpy(orig_name, full_orig_name, namelen);
+  if(!case_sensitive)
+    strupper( orig_name );
 
   /*
    * Check this name doesn't exist in the cache before we 
@@ -193,7 +191,7 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
 
   for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp; 
                         scp = (stat_cache_entry *)ubi_dlNext( scp )) {
-    if(stat_name_equal( scp->orig_name, orig_name) &&
+    if((strcmp( scp->orig_name, orig_name) == 0) &&
        (strcmp( scp->translated_name, translated_path) == 0)) {
       /*
        * Name does exist - promote it.
@@ -231,27 +229,36 @@ static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
  Return True if we translated (and did a scuccessful stat on) the entire name.
 *****************************************************************************/
 
-static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, struct stat *pst)
+static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRUCT_STAT *pst)
 {
   stat_cache_entry *scp;
   stat_cache_entry *longest_hit = NULL;
-  int namelen = strlen(name);
+  pstring chk_name;
+  int namelen;
+
+  if (!lp_stat_cache()) return False;
  
+  namelen = strlen(name);
+
   *start = name;
   global_stat_cache_lookups++;
 
   /*
    * Don't lookup trivial valid directory entries.
    */
-  if(strequal(name, ".") || strequal(name, "..")) {
+  if((*name == '\0') || (strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
     global_stat_cache_misses++;
     return False;
   }
 
+  pstrcpy(chk_name, name);
+  if(!case_sensitive)
+    strupper( chk_name );
+
   for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp; 
                         scp = (stat_cache_entry *)ubi_dlNext( scp )) {
     if(scp->name_len <= namelen) {
-      if(stat_name_equal_len(scp->orig_name, name, scp->name_len)) {
+      if(stat_name_equal_len(scp->orig_name, chk_name, scp->name_len)) {
         if((longest_hit == NULL) || (longest_hit->name_len <= scp->name_len))
           longest_hit = scp;
       }
@@ -275,7 +282,7 @@ static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, struct s
    * and then promote it to the top.
    */
 
-  if(sys_stat( longest_hit->translated_name, pst) != 0) {
+  if(dos_stat( longest_hit->translated_name, pst) != 0) {
     /*
      * Discard this entry.
      */
@@ -322,20 +329,25 @@ of a pathname does not exist.
 ****************************************************************************/
 
 BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, 
-                  BOOL *bad_path, struct stat *pst)
+                  BOOL *bad_path, SMB_STRUCT_STAT *pst)
 {
-  struct stat st;
+  SMB_STRUCT_STAT st;
   char *start, *end, *orig_start;
   pstring dirpath;
   pstring orig_path;
   int saved_errno;
   BOOL component_was_mangled = False;
   BOOL name_has_wildcard = False;
+#if 0
+  /* Andrew's conservative code... JRA. */
+  extern char magic_char;
+#endif
 
   *dirpath = 0;
   *bad_path = False;
-  if(pst)
-    memset( (char *)pst, '\0', sizeof(struct stat));
+  if(pst) {
+         ZERO_STRUCTP(pst);
+  }
 
   if(saved_last_component)
     *saved_last_component = 0;
@@ -354,6 +366,17 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
 
   trim_string(name,"/","/");
 
+  /*
+   * If we trimmed down to a single '\0' character
+   * then we should use the "." directory to avoid
+   * searching the cache.
+   */
+
+  if(!*name) {
+    name[0] = '.';
+    name[1] = '\0';
+  }
+
   /*
    * Ensure saved_last_component is valid even if file exists.
    */
@@ -406,7 +429,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
    * stat the name - if it exists then we are all done!
    */
 
-  if (sys_stat(name,&st) == 0) {
+  if (dos_stat(name,&st) == 0) {
     stat_cache_add(orig_path, name);
     DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
     if(pst)
@@ -431,6 +454,21 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
   if(strchr(start,'?') || strchr(start,'*'))
     name_has_wildcard = True;
 
+  /* 
+   * is_mangled() was changed to look at an entire pathname, not 
+   * just a component. JRA.
+   */
+
+  if(is_mangled(start))
+    component_was_mangled = True;
+
+#if 0
+  /* Keep Andrew's conservative code around, just in case. JRA. */
+  /* this is an extremely conservative test for mangled names. */
+  if (strchr(start,magic_char))
+    component_was_mangled = True;
+#endif
+
   /* 
    * Now we need to recursively match the name against the real 
    * directory structure.
@@ -459,7 +497,7 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
       /* 
        * Check if the name exists up to this point.
        */
-      if (sys_stat(name, &st) == 0) {
+      if (dos_stat(name, &st) == 0) {
         /*
          * It exists. it must either be a directory or this must be
          * the last part of the path for it to be OK.
@@ -527,7 +565,6 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
            */
 
           if (is_mangled(start)) {
-            component_was_mangled = True;
             check_mangled_cache( start );
           }
 
@@ -611,8 +648,8 @@ BOOL check_name(char *name,connection_struct *conn)
 #ifdef S_ISLNK
   if (!lp_symlinks(SNUM(conn)))
     {
-      struct stat statbuf;
-      if ( (sys_lstat(name,&statbuf) != -1) &&
+      SMB_STRUCT_STAT statbuf;
+      if ( (dos_lstat(name,&statbuf) != -1) &&
           (S_ISLNK(statbuf.st_mode)) )
         {
           DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
@@ -633,7 +670,7 @@ scan a directory to find a filename, matching without case sensitivity
 
 If the name looks like a mangled name then try via the mangling functions
 ****************************************************************************/
-BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache)
+static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache)
 {
   void *cur_dir;
   char *dname;