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