Fixed *very* subtle statcache bug where invalid stat state could be
[tprouty/samba.git] / source / smbd / filename.c
1 #define OLD_NTDOMAIN 1
2
3 /* 
4    Unix SMB/Netbios implementation.
5    Version 1.9.
6    filename handling routines
7    Copyright (C) Andrew Tridgell 1992-1998
8    Copyright (C) Jeremy Allison 1999-200
9    Copyright (C) Ying Chen 2000
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 /*
27  * New hash table stat cache code added by Ying Chen.
28  */
29
30 #include "includes.h"
31
32 extern int DEBUGLEVEL;
33 extern BOOL case_sensitive;
34 extern BOOL case_preserve;
35 extern BOOL short_case_preserve;
36 extern fstring remote_machine;
37 extern BOOL use_mangled_map;
38
39 static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache);
40
41 /****************************************************************************
42  Check if two filenames are equal.
43  This needs to be careful about whether we are case sensitive.
44 ****************************************************************************/
45 static BOOL fname_equal(char *name1, char *name2)
46 {
47   int l1 = strlen(name1);
48   int l2 = strlen(name2);
49
50   /* handle filenames ending in a single dot */
51   if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot())
52     {
53       BOOL ret;
54       name1[l1-1] = 0;
55       ret = fname_equal(name1,name2);
56       name1[l1-1] = '.';
57       return(ret);
58     }
59
60   if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot())
61     {
62       BOOL ret;
63       name2[l2-1] = 0;
64       ret = fname_equal(name1,name2);
65       name2[l2-1] = '.';
66       return(ret);
67     }
68
69   /* now normal filename handling */
70   if (case_sensitive)
71     return(strcmp(name1,name2) == 0);
72
73   return(strequal(name1,name2));
74 }
75
76
77 /****************************************************************************
78  Mangle the 2nd name and check if it is then equal to the first name.
79 ****************************************************************************/
80 static BOOL mangled_equal(char *name1, char *name2)
81 {
82   pstring tmpname;
83
84   if (is_8_3(name2, True))
85     return(False);
86
87   pstrcpy(tmpname,name2);
88   mangle_name_83(tmpname);
89
90   return(strequal(name1,tmpname));
91 }
92
93
94 /****************************************************************************
95 This routine is called to convert names from the dos namespace to unix
96 namespace. It needs to handle any case conversions, mangling, format
97 changes etc.
98
99 We assume that we have already done a chdir() to the right "root" directory
100 for this service.
101
102 The function will return False if some part of the name except for the last
103 part cannot be resolved
104
105 If the saved_last_component != 0, then the unmodified last component
106 of the pathname is returned there. This is used in an exceptional
107 case in reply_mv (so far). If saved_last_component == 0 then nothing
108 is returned there.
109
110 The bad_path arg is set to True if the filename walk failed. This is
111 used to pick the correct error code to return between ENOENT and ENOTDIR
112 as Windows applications depend on ERRbadpath being returned if a component
113 of a pathname does not exist.
114
115 On exit from unix_convert, if *pst was not null, then the file stat
116 struct will be returned if the file exists and was found, if not this
117 stat struct will be filled with zeros (and this can be detected by checking
118 for nlinks = 0, which can never be true for any file).
119 ****************************************************************************/
120
121 BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, 
122                   BOOL *bad_path, SMB_STRUCT_STAT *pst)
123 {
124   SMB_STRUCT_STAT st;
125   char *start, *end;
126   pstring dirpath;
127   pstring orig_path;
128   BOOL component_was_mangled = False;
129   BOOL name_has_wildcard = False;
130 #if 0
131   /* Andrew's conservative code... JRA. */
132   extern char magic_char;
133 #endif
134
135   ZERO_STRUCTP(pst);
136
137   *dirpath = 0;
138   *bad_path = False;
139   if(saved_last_component)
140     *saved_last_component = 0;
141
142   if (conn->printer) {
143           /* we don't ever use the filenames on a printer share as a
144              filename - so don't convert them */
145           return True;
146   }
147
148   DEBUG(5, ("unix_convert called on file \"%s\"\n", name));
149
150   /* 
151    * Convert to basic unix format - removing \ chars and cleaning it up.
152    */
153
154   unix_format(name);
155   unix_clean_name(name);
156
157   /* 
158    * Names must be relative to the root of the service - trim any leading /.
159    * also trim trailing /'s.
160    */
161
162   trim_string(name,"/","/");
163
164   /*
165    * If we trimmed down to a single '\0' character
166    * then we should use the "." directory to avoid
167    * searching the cache, but not if we are in a
168    * printing share.
169    */
170
171   if (!*name) {
172     name[0] = '.';
173     name[1] = '\0';
174   }
175
176   /*
177    * Ensure saved_last_component is valid even if file exists.
178    */
179
180   if(saved_last_component) {
181     end = strrchr(name, '/');
182     if(end)
183       pstrcpy(saved_last_component, end + 1);
184     else
185       pstrcpy(saved_last_component, name);
186   }
187
188   if (!case_sensitive && 
189       (!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
190     strnorm(name);
191
192   /*
193    * If we trimmed down to a single '\0' character
194    * then we will be using the "." directory.
195    * As we know this is valid we can return true here.
196    */
197
198   if(!*name)
199     return(True);
200
201   start = name;
202   while (strncmp(start,"./",2) == 0)
203     start += 2;
204
205   pstrcpy(orig_path, name);
206
207   if(stat_cache_lookup(conn, name, dirpath, &start, &st)) {
208     *pst = st;
209     return True;
210   }
211
212   /* 
213    * stat the name - if it exists then we are all done!
214    */
215
216   if (vfs_stat(conn,name,&st) == 0) {
217     stat_cache_add(orig_path, name);
218     DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
219     *pst = st;
220     return(True);
221   }
222
223   DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
224         name, dirpath, start));
225
226   /* 
227    * A special case - if we don't have any mangling chars and are case
228    * sensitive then searching won't help.
229    */
230
231   if (case_sensitive && !is_mangled(name) && 
232       !lp_strip_dot() && !use_mangled_map)
233     return(False);
234
235   name_has_wildcard = ms_has_wild(start);
236
237   /* 
238    * is_mangled() was changed to look at an entire pathname, not 
239    * just a component. JRA.
240    */
241
242   if(is_mangled(start))
243     component_was_mangled = True;
244
245 #if 0
246   /* Keep Andrew's conservative code around, just in case. JRA. */
247   /* this is an extremely conservative test for mangled names. */
248   if (strchr(start,magic_char))
249     component_was_mangled = True;
250 #endif
251
252   /* 
253    * Now we need to recursively match the name against the real 
254    * directory structure.
255    */
256
257   /* 
258    * Match each part of the path name separately, trying the names
259    * as is first, then trying to scan the directory for matching names.
260    */
261
262   for (; start ; start = (end?end+1:(char *)NULL)) {
263       /* 
264        * Pinpoint the end of this section of the filename.
265        */
266       end = strchr(start, '/');
267
268       /* 
269        * Chop the name at this point.
270        */
271       if (end) 
272         *end = 0;
273
274       if(saved_last_component != 0)
275         pstrcpy(saved_last_component, end ? end + 1 : start);
276
277       /* 
278        * Check if the name exists up to this point.
279        */
280
281       if (vfs_stat(conn,name, &st) == 0) {
282         /*
283          * It exists. it must either be a directory or this must be
284          * the last part of the path for it to be OK.
285          */
286         if (end && !(st.st_mode & S_IFDIR)) {
287           /*
288            * An intermediate part of the name isn't a directory.
289             */
290           DEBUG(5,("Not a dir %s\n",start));
291           *end = '/';
292           return(False);
293         }
294
295       } else {
296         pstring rest;
297
298                 /* Stat failed - ensure we don't use it. */
299         ZERO_STRUCT(st);
300         *rest = 0;
301
302         /*
303          * Remember the rest of the pathname so it can be restored
304          * later.
305          */
306
307         if (end)
308           pstrcpy(rest,end+1);
309
310         /*
311          * Try to find this part of the path in the directory.
312          */
313
314         if (ms_has_wild(start) || !scan_directory(dirpath, start, conn, end?True:False)) {
315           if (end) {
316             /*
317              * An intermediate part of the name can't be found.
318              */
319             DEBUG(5,("Intermediate not found %s\n",start));
320             *end = '/';
321
322             /* 
323              * We need to return the fact that the intermediate
324              * name resolution failed. This is used to return an
325              * error of ERRbadpath rather than ERRbadfile. Some
326              * Windows applications depend on the difference between
327              * these two errors.
328              */
329             *bad_path = True;
330             return(False);
331           }
332               
333           /* 
334            * Just the last part of the name doesn't exist.
335                * We may need to strupper() or strlower() it in case
336            * this conversion is being used for file creation 
337            * purposes. If the filename is of mixed case then 
338            * don't normalise it.
339            */
340
341           if (!case_preserve && (!strhasupper(start) || !strhaslower(start)))           
342             strnorm(start);
343
344           /*
345            * check on the mangled stack to see if we can recover the 
346            * base of the filename.
347            */
348
349           if (is_mangled(start)) {
350             check_mangled_cache( start );
351           }
352
353           DEBUG(5,("New file %s\n",start));
354           return(True); 
355         }
356
357       /* 
358        * Restore the rest of the string.
359        */
360       if (end) {
361         pstrcpy(start+strlen(start)+1,rest);
362         end = start + strlen(start);
363       }
364     } /* end else */
365
366     /* 
367      * Add to the dirpath that we have resolved so far.
368      */
369     if (*dirpath)
370       pstrcat(dirpath,"/");
371
372     pstrcat(dirpath,start);
373
374     /*
375      * Don't cache a name with mangled or wildcard components
376      * as this can change the size.
377      */
378
379     if(!component_was_mangled && !name_has_wildcard)
380       stat_cache_add(orig_path, dirpath);
381
382     /* 
383      * Restore the / that we wiped out earlier.
384      */
385     if (end)
386       *end = '/';
387   }
388   
389   /*
390    * Don't cache a name with mangled or wildcard components
391    * as this can change the size.
392    */
393
394   if(!component_was_mangled && !name_has_wildcard)
395     stat_cache_add(orig_path, name);
396
397   /*
398    * If we ended up resolving the entire path then return a valid
399    * stat struct if we got one.
400    */
401
402   if (VALID_STAT(st) && (strlen(orig_path) == strlen(name)))
403     *pst = st;
404
405   /* 
406    * The name has been resolved.
407    */
408
409   DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
410   return(True);
411 }
412
413
414 /****************************************************************************
415 check a filename - possibly caling reducename
416
417 This is called by every routine before it allows an operation on a filename.
418 It does any final confirmation necessary to ensure that the filename is
419 a valid one for the user to access.
420 ****************************************************************************/
421 BOOL check_name(char *name,connection_struct *conn)
422 {
423   BOOL ret;
424
425   errno = 0;
426
427   if (IS_VETO_PATH(conn, name))  {
428           DEBUG(5,("file path name %s vetoed\n",name));
429           return(0);
430   }
431
432   ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn)));
433
434   /* Check if we are allowing users to follow symlinks */
435   /* Patch from David Clerc <David.Clerc@cui.unige.ch>
436      University of Geneva */
437
438 #ifdef S_ISLNK
439   if (!lp_symlinks(SNUM(conn))) {
440       SMB_STRUCT_STAT statbuf;
441       if ( (conn->vfs_ops.lstat(conn,dos_to_unix(name,False),&statbuf) != -1) &&
442                 (S_ISLNK(statbuf.st_mode)) ) {
443           DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
444           ret=0; 
445       }
446     }
447 #endif
448
449   if (!ret)
450     DEBUG(5,("check_name on %s failed\n",name));
451
452   return(ret);
453 }
454
455
456 /****************************************************************************
457 scan a directory to find a filename, matching without case sensitivity
458
459 If the name looks like a mangled name then try via the mangling functions
460 ****************************************************************************/
461 static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache)
462 {
463   void *cur_dir;
464   char *dname;
465   BOOL mangled;
466   pstring name2;
467
468   mangled = is_mangled(name);
469
470   /* handle null paths */
471   if (*path == 0)
472     path = ".";
473
474   if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) {
475     pstrcpy(name, dname);       
476     return(True);
477   }      
478
479   /*
480    * The incoming name can be mangled, and if we de-mangle it
481    * here it will not compare correctly against the filename (name2)
482    * read from the directory and then mangled by the name_map_mangle()
483    * call. We need to mangle both names or neither.
484    * (JRA).
485    */
486   if (mangled)
487     mangled = !check_mangled_cache( name );
488
489   /* open the directory */
490   if (!(cur_dir = OpenDir(conn, path, True))) {
491       DEBUG(3,("scan dir didn't open dir [%s]\n",path));
492       return(False);
493   }
494
495   /* now scan for matching names */
496   while ((dname = ReadDirName(cur_dir))) {
497       if (*dname == '.' && (strequal(dname,".") || strequal(dname,"..")))
498         continue;
499
500       pstrcpy(name2,dname);
501       if (!name_map_mangle(name2,False,True,SNUM(conn)))
502         continue;
503
504       if ((mangled && mangled_equal(name,name2)) || fname_equal(name, name2)) {
505         /* we've found the file, change it's name and return */
506         if (docache)
507           DirCacheAdd(path,name,dname,SNUM(conn));
508         pstrcpy(name, dname);
509         CloseDir(cur_dir);
510         return(True);
511     }
512   }
513
514   CloseDir(cur_dir);
515   return(False);
516 }
517
518
519 #undef OLD_NTDOMAIN