Restructuring of vfs layer to include a "this" pointer - can be an fsp or
[kamenim/samba-autobuild/.git] / source3 / 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
116 BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, 
117                   BOOL *bad_path, SMB_STRUCT_STAT *pst)
118 {
119   SMB_STRUCT_STAT st;
120   char *start, *end;
121   pstring dirpath;
122   pstring orig_path;
123   BOOL component_was_mangled = False;
124   BOOL name_has_wildcard = False;
125 #if 0
126   /* Andrew's conservative code... JRA. */
127   extern char magic_char;
128 #endif
129
130   if (conn->printer) {
131           /* we don't ever use the filenames on a printer share as a
132              filename - so don't convert them */
133           return True;
134   }
135
136   DEBUG(5, ("unix_convert called on file \"%s\"\n", name));
137
138   *dirpath = 0;
139   *bad_path = False;
140   if(pst) {
141     ZERO_STRUCTP(pst);
142   }
143
144   if(saved_last_component)
145     *saved_last_component = 0;
146
147   /* 
148    * Convert to basic unix format - removing \ chars and cleaning it up.
149    */
150
151   unix_format(name);
152   unix_clean_name(name);
153
154   /* 
155    * Names must be relative to the root of the service - trim any leading /.
156    * also trim trailing /'s.
157    */
158
159   trim_string(name,"/","/");
160
161   /*
162    * If we trimmed down to a single '\0' character
163    * then we should use the "." directory to avoid
164    * searching the cache, but not if we are in a
165    * printing share.
166    */
167
168   if (!*name && (!conn -> printer)) {
169     name[0] = '.';
170     name[1] = '\0';
171   }
172
173   /*
174    * Ensure saved_last_component is valid even if file exists.
175    */
176
177   if(saved_last_component) {
178     end = strrchr(name, '/');
179     if(end)
180       pstrcpy(saved_last_component, end + 1);
181     else
182       pstrcpy(saved_last_component, name);
183   }
184
185   if (!case_sensitive && 
186       (!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
187     strnorm(name);
188
189   /*
190    * If we trimmed down to a single '\0' character
191    * then we will be using the "." directory.
192    * As we know this is valid we can return true here.
193    */
194
195   if(!*name)
196     return(True);
197
198   start = name;
199   while (strncmp(start,"./",2) == 0)
200     start += 2;
201
202   pstrcpy(orig_path, name);
203
204   if(stat_cache_lookup(conn, name, dirpath, &start, &st)) {
205     if(pst)
206       *pst = st;
207     return True;
208   }
209
210   /* 
211    * stat the name - if it exists then we are all done!
212    */
213
214   if (conn->vfs_ops.stat(conn,dos_to_unix(name,False),&st) == 0) {
215     stat_cache_add(orig_path, name);
216     DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
217     if(pst)
218       *pst = st;
219     return(True);
220   }
221
222   DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
223         name, dirpath, start));
224
225   /* 
226    * A special case - if we don't have any mangling chars and are case
227    * sensitive then searching won't help.
228    */
229
230   if (case_sensitive && !is_mangled(name) && 
231       !lp_strip_dot() && !use_mangled_map)
232     return(False);
233
234   name_has_wildcard = ms_has_wild(start);
235
236   /* 
237    * is_mangled() was changed to look at an entire pathname, not 
238    * just a component. JRA.
239    */
240
241   if(is_mangled(start))
242     component_was_mangled = True;
243
244 #if 0
245   /* Keep Andrew's conservative code around, just in case. JRA. */
246   /* this is an extremely conservative test for mangled names. */
247   if (strchr(start,magic_char))
248     component_was_mangled = True;
249 #endif
250
251   /* 
252    * Now we need to recursively match the name against the real 
253    * directory structure.
254    */
255
256   /* 
257    * Match each part of the path name separately, trying the names
258    * as is first, then trying to scan the directory for matching names.
259    */
260
261   for (; start ; start = (end?end+1:(char *)NULL)) {
262       /* 
263        * Pinpoint the end of this section of the filename.
264        */
265       end = strchr(start, '/');
266
267       /* 
268        * Chop the name at this point.
269        */
270       if (end) 
271         *end = 0;
272
273       if(saved_last_component != 0)
274         pstrcpy(saved_last_component, end ? end + 1 : start);
275
276       /* 
277        * Check if the name exists up to this point.
278        */
279
280       if (conn->vfs_ops.stat(conn,dos_to_unix(name,False), &st) == 0) {
281         /*
282          * It exists. it must either be a directory or this must be
283          * the last part of the path for it to be OK.
284          */
285         if (end && !(st.st_mode & S_IFDIR)) {
286           /*
287            * An intermediate part of the name isn't a directory.
288             */
289           DEBUG(5,("Not a dir %s\n",start));
290           *end = '/';
291           return(False);
292         }
293
294       } else {
295         pstring rest;
296
297         *rest = 0;
298
299         /*
300          * Remember the rest of the pathname so it can be restored
301          * later.
302          */
303
304         if (end)
305           pstrcpy(rest,end+1);
306
307         /*
308          * Try to find this part of the path in the directory.
309          */
310
311         if (ms_has_wild(start) ||
312             !scan_directory(dirpath, start, conn, end?True:False)) {
313           if (end) {
314             /*
315              * An intermediate part of the name can't be found.
316              */
317             DEBUG(5,("Intermediate not found %s\n",start));
318             *end = '/';
319
320             /* 
321              * We need to return the fact that the intermediate
322              * name resolution failed. This is used to return an
323              * error of ERRbadpath rather than ERRbadfile. Some
324              * Windows applications depend on the difference between
325              * these two errors.
326              */
327             *bad_path = True;
328             return(False);
329           }
330               
331           /* 
332            * Just the last part of the name doesn't exist.
333                * We may need to strupper() or strlower() it in case
334            * this conversion is being used for file creation 
335            * purposes. If the filename is of mixed case then 
336            * don't normalise it.
337            */
338
339           if (!case_preserve && (!strhasupper(start) || !strhaslower(start)))           
340             strnorm(start);
341
342           /*
343            * check on the mangled stack to see if we can recover the 
344            * base of the filename.
345            */
346
347           if (is_mangled(start)) {
348             check_mangled_cache( start );
349           }
350
351           DEBUG(5,("New file %s\n",start));
352           return(True); 
353         }
354
355       /* 
356        * Restore the rest of the string.
357        */
358       if (end) {
359         pstrcpy(start+strlen(start)+1,rest);
360         end = start + strlen(start);
361       }
362     } /* end else */
363
364     /* 
365      * Add to the dirpath that we have resolved so far.
366      */
367     if (*dirpath)
368       pstrcat(dirpath,"/");
369
370     pstrcat(dirpath,start);
371
372     /*
373      * Don't cache a name with mangled or wildcard components
374      * as this can change the size.
375      */
376
377     if(!component_was_mangled && !name_has_wildcard)
378       stat_cache_add(orig_path, dirpath);
379
380     /* 
381      * Restore the / that we wiped out earlier.
382      */
383     if (end)
384       *end = '/';
385   }
386   
387   /*
388    * Don't cache a name with mangled or wildcard components
389    * as this can change the size.
390    */
391
392   if(!component_was_mangled && !name_has_wildcard)
393     stat_cache_add(orig_path, name);
394
395   /* 
396    * The name has been resolved.
397    */
398
399   DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
400   return(True);
401 }
402
403
404 /****************************************************************************
405 check a filename - possibly caling reducename
406
407 This is called by every routine before it allows an operation on a filename.
408 It does any final confirmation necessary to ensure that the filename is
409 a valid one for the user to access.
410 ****************************************************************************/
411 BOOL check_name(char *name,connection_struct *conn)
412 {
413   BOOL ret;
414
415   errno = 0;
416
417   if (IS_VETO_PATH(conn, name))  {
418           DEBUG(5,("file path name %s vetoed\n",name));
419           return(0);
420   }
421
422   ret = reduce_name(conn,name,conn->connectpath,lp_widelinks(SNUM(conn)));
423
424   /* Check if we are allowing users to follow symlinks */
425   /* Patch from David Clerc <David.Clerc@cui.unige.ch>
426      University of Geneva */
427
428 #ifdef S_ISLNK
429   if (!lp_symlinks(SNUM(conn)))
430     {
431       SMB_STRUCT_STAT statbuf;
432       if ( (conn->vfs_ops.lstat(conn,dos_to_unix(name,False),&statbuf) != -1) &&
433           (S_ISLNK(statbuf.st_mode)) )
434         {
435           DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
436           ret=0; 
437         }
438     }
439 #endif
440
441   if (!ret)
442     DEBUG(5,("check_name on %s failed\n",name));
443
444   return(ret);
445 }
446
447
448 /****************************************************************************
449 scan a directory to find a filename, matching without case sensitivity
450
451 If the name looks like a mangled name then try via the mangling functions
452 ****************************************************************************/
453 static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache)
454 {
455   void *cur_dir;
456   char *dname;
457   BOOL mangled;
458   pstring name2;
459
460   mangled = is_mangled(name);
461
462   /* handle null paths */
463   if (*path == 0)
464     path = ".";
465
466   if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) {
467     pstrcpy(name, dname);       
468     return(True);
469   }      
470
471   /*
472    * The incoming name can be mangled, and if we de-mangle it
473    * here it will not compare correctly against the filename (name2)
474    * read from the directory and then mangled by the name_map_mangle()
475    * call. We need to mangle both names or neither.
476    * (JRA).
477    */
478   if (mangled)
479     mangled = !check_mangled_cache( name );
480
481   /* open the directory */
482   if (!(cur_dir = OpenDir(conn, path, True))) 
483     {
484       DEBUG(3,("scan dir didn't open dir [%s]\n",path));
485       return(False);
486     }
487
488   /* now scan for matching names */
489   while ((dname = ReadDirName(cur_dir))) 
490     {
491       if (*dname == '.' &&
492           (strequal(dname,".") || strequal(dname,"..")))
493         continue;
494
495       pstrcpy(name2,dname);
496       if (!name_map_mangle(name2,False,True,SNUM(conn)))
497         continue;
498
499       if ((mangled && mangled_equal(name,name2))
500           || fname_equal(name, name2))
501         {
502           /* we've found the file, change it's name and return */
503           if (docache) DirCacheAdd(path,name,dname,SNUM(conn));
504           pstrcpy(name, dname);
505           CloseDir(cur_dir);
506           return(True);
507         }
508     }
509
510   CloseDir(cur_dir);
511   return(False);
512 }
513
514
515 #undef OLD_NTDOMAIN