caba4064d7b081a2be3b56f3e81d1ab52aaa5c11
[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    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25 extern BOOL case_sensitive;
26 extern BOOL case_preserve;
27 extern BOOL short_case_preserve;
28 extern fstring remote_machine;
29 extern BOOL use_mangled_map;
30
31 static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache);
32
33 /****************************************************************************
34  Check if two filenames are equal.
35  This needs to be careful about whether we are case sensitive.
36 ****************************************************************************/
37 static BOOL fname_equal(char *name1, char *name2)
38 {
39   int l1 = strlen(name1);
40   int l2 = strlen(name2);
41
42   /* handle filenames ending in a single dot */
43   if (l1-l2 == 1 && name1[l1-1] == '.' && lp_strip_dot())
44     {
45       BOOL ret;
46       name1[l1-1] = 0;
47       ret = fname_equal(name1,name2);
48       name1[l1-1] = '.';
49       return(ret);
50     }
51
52   if (l2-l1 == 1 && name2[l2-1] == '.' && lp_strip_dot())
53     {
54       BOOL ret;
55       name2[l2-1] = 0;
56       ret = fname_equal(name1,name2);
57       name2[l2-1] = '.';
58       return(ret);
59     }
60
61   /* now normal filename handling */
62   if (case_sensitive)
63     return(strcmp(name1,name2) == 0);
64
65   return(strequal(name1,name2));
66 }
67
68
69 /****************************************************************************
70  Mangle the 2nd name and check if it is then equal to the first name.
71 ****************************************************************************/
72 static BOOL mangled_equal(char *name1, char *name2)
73 {
74   pstring tmpname;
75
76   if (is_8_3(name2, True))
77     return(False);
78
79   pstrcpy(tmpname,name2);
80   mangle_name_83(tmpname);
81
82   return(strequal(name1,tmpname));
83 }
84
85 /****************************************************************************
86  Stat cache code used in unix_convert.
87 *****************************************************************************/
88
89 static int global_stat_cache_lookups;
90 static int global_stat_cache_misses;
91 static int global_stat_cache_hits;
92
93 /****************************************************************************
94  Stat cache statistics code.
95 *****************************************************************************/
96
97 void print_stat_cache_statistics(void)
98 {
99   double eff = (100.0* (double)global_stat_cache_hits)/(double)global_stat_cache_lookups;
100
101   DEBUG(0,("stat cache stats: lookups = %d, hits = %d, misses = %d, \
102 stat cache was %f%% effective.\n", global_stat_cache_lookups,
103        global_stat_cache_hits, global_stat_cache_misses, eff ));
104 }
105
106 typedef struct {
107   ubi_dlNode link;
108   int name_len;
109   pstring orig_name;
110   pstring translated_name;
111 } stat_cache_entry;
112
113 #define MAX_STAT_CACHE_SIZE 50
114
115 static ubi_dlList stat_cache = { NULL, (ubi_dlNodePtr)&stat_cache, 0};
116
117 /****************************************************************************
118  Compare a pathname to a name in the stat cache - of a given length.
119  Note - this code always checks that the next character in the pathname
120  is either a '/' character, or a '\0' character - to ensure we only
121  match *full* pathname components. Note we don't need to handle case
122  here, if we're case insensitive the stat cache orig names are all upper
123  case.
124 *****************************************************************************/
125
126 static BOOL stat_name_equal_len( char *stat_name, char *orig_name, int len)
127 {
128   BOOL matched = (memcmp( stat_name, orig_name, len) == 0);
129   if(orig_name[len] != '/' && orig_name[len] != '\0')
130     return False;
131
132   return matched;
133 }
134
135 /****************************************************************************
136  Add an entry into the stat cache.
137 *****************************************************************************/
138
139 static void stat_cache_add( char *full_orig_name, char *orig_translated_path)
140 {
141   stat_cache_entry *scp;
142   pstring orig_name;
143   pstring translated_path;
144   int namelen;
145
146   if (!lp_stat_cache()) return;
147
148   namelen = strlen(orig_translated_path);
149
150   /*
151    * Don't cache trivial valid directory entries.
152    */
153   if((strcmp(full_orig_name, ".") == 0) || (strcmp(full_orig_name, "..") == 0))
154     return;
155
156   /*
157    * If we are in case insentive mode, we need to
158    * store names that need no translation - else, it
159    * would be a waste.
160    */
161
162   if(case_sensitive && (strcmp(full_orig_name, orig_translated_path) == 0))
163     return;
164
165   /*
166    * Remove any trailing '/' characters from the
167    * translated path.
168    */
169
170   pstrcpy(translated_path, orig_translated_path);
171   if(translated_path[namelen-1] == '/') {
172     translated_path[namelen-1] = '\0';
173     namelen--;
174   }
175
176   /*
177    * We will only replace namelen characters 
178    * of full_orig_name.
179    * StrnCpy always null terminates.
180    */
181
182   StrnCpy(orig_name, full_orig_name, namelen);
183   if(!case_sensitive)
184     strupper( orig_name );
185
186   /*
187    * Check this name doesn't exist in the cache before we 
188    * add it.
189    */
190
191   for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp; 
192                         scp = (stat_cache_entry *)ubi_dlNext( scp )) {
193     if((strcmp( scp->orig_name, orig_name) == 0) &&
194        (strcmp( scp->translated_name, translated_path) == 0)) {
195       /*
196        * Name does exist - promote it.
197        */
198       if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != scp ) {
199         ubi_dlRemThis( &stat_cache, scp);
200         ubi_dlAddHead( &stat_cache, scp);
201       }
202       return;
203     }
204   }
205
206   if((scp = (stat_cache_entry *)malloc(sizeof(stat_cache_entry))) == NULL) {
207     DEBUG(0,("stat_cache_add: Out of memory !\n"));
208     return;
209   }
210
211   pstrcpy(scp->orig_name, orig_name);
212   pstrcpy(scp->translated_name, translated_path);
213   scp->name_len = namelen;
214
215   ubi_dlAddHead( &stat_cache, scp);
216
217   DEBUG(10,("stat_cache_add: Added entry %s -> %s\n", scp->orig_name, scp->translated_name ));
218
219   if(ubi_dlCount(&stat_cache) > lp_stat_cache_size()) {
220     scp = (stat_cache_entry *)ubi_dlRemTail( &stat_cache );
221     free((char *)scp);
222     return;
223   }
224 }
225
226 /****************************************************************************
227  Look through the stat cache for an entry - promote it to the top if found.
228  Return True if we translated (and did a scuccessful stat on) the entire name.
229 *****************************************************************************/
230
231 static BOOL stat_cache_lookup( char *name, char *dirpath, char **start, SMB_STRUCT_STAT *pst)
232 {
233   stat_cache_entry *scp;
234   stat_cache_entry *longest_hit = NULL;
235   pstring chk_name;
236   int namelen;
237
238   if (!lp_stat_cache()) return False;
239  
240   namelen = strlen(name);
241
242   *start = name;
243   global_stat_cache_lookups++;
244
245   /*
246    * Don't lookup trivial valid directory entries.
247    */
248   if((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
249     global_stat_cache_misses++;
250     return False;
251   }
252
253   pstrcpy(chk_name, name);
254   if(!case_sensitive)
255     strupper( chk_name );
256
257   for( scp = (stat_cache_entry *)ubi_dlFirst( &stat_cache); scp; 
258                         scp = (stat_cache_entry *)ubi_dlNext( scp )) {
259     if(scp->name_len <= namelen) {
260       if(stat_name_equal_len(scp->orig_name, chk_name, scp->name_len)) {
261         if((longest_hit == NULL) || (longest_hit->name_len <= scp->name_len))
262           longest_hit = scp;
263       }
264     }
265   }
266
267   if(longest_hit == NULL) {
268     DEBUG(10,("stat_cache_lookup: cache miss on %s\n", name));
269     global_stat_cache_misses++;
270     return False;
271   }
272
273   global_stat_cache_hits++;
274
275   DEBUG(10,("stat_cache_lookup: cache hit for name %s. %s -> %s\n",
276         name, longest_hit->orig_name, longest_hit->translated_name ));
277
278   /*
279    * longest_hit is the longest match we got in the list.
280    * Check it exists - if so, overwrite the original name
281    * and then promote it to the top.
282    */
283
284   if(dos_stat( longest_hit->translated_name, pst) != 0) {
285     /*
286      * Discard this entry.
287      */
288     ubi_dlRemThis( &stat_cache, longest_hit);
289     free((char *)longest_hit);
290     return False;
291   }
292
293   memcpy(name, longest_hit->translated_name, longest_hit->name_len);
294   if( (stat_cache_entry *)ubi_dlFirst( &stat_cache) != longest_hit ) {
295     ubi_dlRemThis( &stat_cache, longest_hit);
296     ubi_dlAddHead( &stat_cache, longest_hit);
297   }
298
299   *start = &name[longest_hit->name_len];
300   if(**start == '/')
301     ++*start;
302
303   StrnCpy( dirpath, longest_hit->translated_name, name - (*start));
304
305   return (namelen == longest_hit->name_len);
306 }
307
308 /****************************************************************************
309 This routine is called to convert names from the dos namespace to unix
310 namespace. It needs to handle any case conversions, mangling, format
311 changes etc.
312
313 We assume that we have already done a chdir() to the right "root" directory
314 for this service.
315
316 The function will return False if some part of the name except for the last
317 part cannot be resolved
318
319 If the saved_last_component != 0, then the unmodified last component
320 of the pathname is returned there. This is used in an exceptional
321 case in reply_mv (so far). If saved_last_component == 0 then nothing
322 is returned there.
323
324 The bad_path arg is set to True if the filename walk failed. This is
325 used to pick the correct error code to return between ENOENT and ENOTDIR
326 as Windows applications depend on ERRbadpath being returned if a component
327 of a pathname does not exist.
328 ****************************************************************************/
329
330 BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, 
331                   BOOL *bad_path, SMB_STRUCT_STAT *pst)
332 {
333   SMB_STRUCT_STAT st;
334   char *start, *end, *orig_start;
335   pstring dirpath;
336   pstring orig_path;
337   int saved_errno;
338   BOOL component_was_mangled = False;
339   BOOL name_has_wildcard = False;
340 #if 0
341   /* Andrew's conservative code... JRA. */
342   extern char magic_char;
343 #endif
344
345   *dirpath = 0;
346   *bad_path = False;
347   if(pst) {
348           ZERO_STRUCTP(pst);
349   }
350
351   if(saved_last_component)
352     *saved_last_component = 0;
353
354   /* 
355    * Convert to basic unix format - removing \ chars and cleaning it up.
356    */
357
358   unix_format(name);
359   unix_clean_name(name);
360
361   /* 
362    * Names must be relative to the root of the service - trim any leading /.
363    * also trim trailing /'s.
364    */
365
366   trim_string(name,"/","/");
367
368   /*
369    * Ensure saved_last_component is valid even if file exists.
370    */
371
372   if(saved_last_component) {
373     end = strrchr(name, '/');
374     if(end)
375       pstrcpy(saved_last_component, end + 1);
376     else
377       pstrcpy(saved_last_component, name);
378   }
379
380   if (!case_sensitive && 
381       (!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
382     strnorm(name);
383
384   /* 
385    * Check if it's a printer file.
386    */
387   if (conn->printer) {
388     if ((! *name) || strchr(name,'/') || !is_8_3(name, True)) {
389       char *s;
390       fstring name2;
391       slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine);
392
393       /* 
394        * Sanitise the name.
395        */
396
397       for (s=name2 ; *s ; s++)
398         if (!issafe(*s)) *s = '_';
399           pstrcpy(name,(char *)mktemp(name2));    
400     }      
401     return(True);
402   }
403
404   start = name;
405   while (strncmp(start,"./",2) == 0)
406     start += 2;
407
408   pstrcpy(orig_path, name);
409
410   if(stat_cache_lookup( name, dirpath, &start, &st)) {
411     if(pst)
412       *pst = st;
413     return True;
414   }
415
416   /* 
417    * stat the name - if it exists then we are all done!
418    */
419
420   if (dos_stat(name,&st) == 0) {
421     stat_cache_add(orig_path, name);
422     DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
423     if(pst)
424       *pst = st;
425     return(True);
426   }
427
428   saved_errno = errno;
429
430   DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
431         name, dirpath, start));
432
433   /* 
434    * A special case - if we don't have any mangling chars and are case
435    * sensitive then searching won't help.
436    */
437
438   if (case_sensitive && !is_mangled(name) && 
439       !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
440     return(False);
441
442   if(strchr(start,'?') || strchr(start,'*'))
443     name_has_wildcard = True;
444
445   /* 
446    * is_mangled() was changed to look at an entire pathname, not 
447    * just a component. JRA.
448    */
449
450   if(is_mangled(start))
451     component_was_mangled = True;
452
453 #if 0
454   /* Keep Andrew's conservative code around, just in case. JRA. */
455   /* this is an extremely conservative test for mangled names. */
456   if (strchr(start,magic_char))
457     component_was_mangled = True;
458 #endif
459
460   /* 
461    * Now we need to recursively match the name against the real 
462    * directory structure.
463    */
464
465   /* 
466    * Match each part of the path name separately, trying the names
467    * as is first, then trying to scan the directory for matching names.
468    */
469
470   for (orig_start = start; start ; start = (end?end+1:(char *)NULL)) {
471       /* 
472        * Pinpoint the end of this section of the filename.
473        */
474       end = strchr(start, '/');
475
476       /* 
477        * Chop the name at this point.
478        */
479       if (end) 
480         *end = 0;
481
482       if(saved_last_component != 0)
483         pstrcpy(saved_last_component, end ? end + 1 : start);
484
485       /* 
486        * Check if the name exists up to this point.
487        */
488       if (dos_stat(name, &st) == 0) {
489         /*
490          * It exists. it must either be a directory or this must be
491          * the last part of the path for it to be OK.
492          */
493         if (end && !(st.st_mode & S_IFDIR)) {
494           /*
495            * An intermediate part of the name isn't a directory.
496             */
497           DEBUG(5,("Not a dir %s\n",start));
498           *end = '/';
499           return(False);
500         }
501
502       } else {
503         pstring rest;
504
505         *rest = 0;
506
507         /*
508          * Remember the rest of the pathname so it can be restored
509          * later.
510          */
511
512         if (end)
513           pstrcpy(rest,end+1);
514
515         /*
516          * Try to find this part of the path in the directory.
517          */
518
519         if (strchr(start,'?') || strchr(start,'*') ||
520             !scan_directory(dirpath, start, conn, end?True:False)) {
521           if (end) {
522             /*
523              * An intermediate part of the name can't be found.
524              */
525             DEBUG(5,("Intermediate not found %s\n",start));
526             *end = '/';
527
528             /* 
529              * We need to return the fact that the intermediate
530              * name resolution failed. This is used to return an
531              * error of ERRbadpath rather than ERRbadfile. Some
532              * Windows applications depend on the difference between
533              * these two errors.
534              */
535             *bad_path = True;
536             return(False);
537           }
538               
539           /* 
540            * Just the last part of the name doesn't exist.
541                * We may need to strupper() or strlower() it in case
542            * this conversion is being used for file creation 
543            * purposes. If the filename is of mixed case then 
544            * don't normalise it.
545            */
546
547           if (!case_preserve && (!strhasupper(start) || !strhaslower(start)))           
548             strnorm(start);
549
550           /*
551            * check on the mangled stack to see if we can recover the 
552            * base of the filename.
553            */
554
555           if (is_mangled(start)) {
556             check_mangled_cache( start );
557           }
558
559           DEBUG(5,("New file %s\n",start));
560           return(True); 
561         }
562
563       /* 
564        * Restore the rest of the string.
565        */
566       if (end) {
567         pstrcpy(start+strlen(start)+1,rest);
568         end = start + strlen(start);
569       }
570     } /* end else */
571
572     /* 
573      * Add to the dirpath that we have resolved so far.
574      */
575     if (*dirpath)
576       pstrcat(dirpath,"/");
577
578     pstrcat(dirpath,start);
579
580     /*
581      * Don't cache a name with mangled or wildcard components
582      * as this can change the size.
583      */
584
585     if(!component_was_mangled && !name_has_wildcard)
586       stat_cache_add(orig_path, dirpath);
587
588     /* 
589      * Restore the / that we wiped out earlier.
590      */
591     if (end)
592       *end = '/';
593   }
594   
595   /*
596    * Don't cache a name with mangled or wildcard components
597    * as this can change the size.
598    */
599
600   if(!component_was_mangled && !name_has_wildcard)
601     stat_cache_add(orig_path, name);
602
603   /* 
604    * The name has been resolved.
605    */
606
607   DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
608   return(True);
609 }
610
611
612 /****************************************************************************
613 check a filename - possibly caling reducename
614
615 This is called by every routine before it allows an operation on a filename.
616 It does any final confirmation necessary to ensure that the filename is
617 a valid one for the user to access.
618 ****************************************************************************/
619 BOOL check_name(char *name,connection_struct *conn)
620 {
621   BOOL ret;
622
623   errno = 0;
624
625   if (IS_VETO_PATH(conn, name))  {
626           DEBUG(5,("file path name %s vetoed\n",name));
627           return(0);
628   }
629
630   ret = reduce_name(name,conn->connectpath,lp_widelinks(SNUM(conn)));
631
632   /* Check if we are allowing users to follow symlinks */
633   /* Patch from David Clerc <David.Clerc@cui.unige.ch>
634      University of Geneva */
635
636 #ifdef S_ISLNK
637   if (!lp_symlinks(SNUM(conn)))
638     {
639       SMB_STRUCT_STAT statbuf;
640       if ( (dos_lstat(name,&statbuf) != -1) &&
641           (S_ISLNK(statbuf.st_mode)) )
642         {
643           DEBUG(3,("check_name: denied: file path name %s is a symlink\n",name));
644           ret=0; 
645         }
646     }
647 #endif
648
649   if (!ret)
650     DEBUG(5,("check_name on %s failed\n",name));
651
652   return(ret);
653 }
654
655
656 /****************************************************************************
657 scan a directory to find a filename, matching without case sensitivity
658
659 If the name looks like a mangled name then try via the mangling functions
660 ****************************************************************************/
661 static BOOL scan_directory(char *path, char *name,connection_struct *conn,BOOL docache)
662 {
663   void *cur_dir;
664   char *dname;
665   BOOL mangled;
666   pstring name2;
667
668   mangled = is_mangled(name);
669
670   /* handle null paths */
671   if (*path == 0)
672     path = ".";
673
674   if (docache && (dname = DirCacheCheck(path,name,SNUM(conn)))) {
675     pstrcpy(name, dname);       
676     return(True);
677   }      
678
679   /*
680    * The incoming name can be mangled, and if we de-mangle it
681    * here it will not compare correctly against the filename (name2)
682    * read from the directory and then mangled by the name_map_mangle()
683    * call. We need to mangle both names or neither.
684    * (JRA).
685    */
686   if (mangled)
687     mangled = !check_mangled_cache( name );
688
689   /* open the directory */
690   if (!(cur_dir = OpenDir(conn, path, True))) 
691     {
692       DEBUG(3,("scan dir didn't open dir [%s]\n",path));
693       return(False);
694     }
695
696   /* now scan for matching names */
697   while ((dname = ReadDirName(cur_dir))) 
698     {
699       if (*dname == '.' &&
700           (strequal(dname,".") || strequal(dname,"..")))
701         continue;
702
703       pstrcpy(name2,dname);
704       if (!name_map_mangle(name2,False,SNUM(conn))) continue;
705
706       if ((mangled && mangled_equal(name,name2))
707           || fname_equal(name, name2))
708         {
709           /* we've found the file, change it's name and return */
710           if (docache) DirCacheAdd(path,name,dname,SNUM(conn));
711           pstrcpy(name, dname);
712           CloseDir(cur_dir);
713           return(True);
714         }
715     }
716
717   CloseDir(cur_dir);
718   return(False);
719 }