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