smbd/filename.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    filename handling routines
00004    Copyright (C) Andrew Tridgell 1992-1998
00005    Copyright (C) Jeremy Allison 1999-2004
00006    Copyright (C) Ying Chen 2000
00007    
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 
00023 /*
00024  * New hash table stat cache code added by Ying Chen.
00025  */
00026 
00027 #include "includes.h"
00028 
00029 static BOOL scan_directory(connection_struct *conn, const char *path, char *name,size_t maxlength);
00030 
00031 /****************************************************************************
00032  Check if two filenames are equal.
00033  This needs to be careful about whether we are case sensitive.
00034 ****************************************************************************/
00035 
00036 static BOOL fname_equal(const char *name1, const char *name2, BOOL case_sensitive)
00037 {
00038         /* Normal filename handling */
00039         if (case_sensitive)
00040                 return(strcmp(name1,name2) == 0);
00041 
00042         return(strequal(name1,name2));
00043 }
00044 
00045 /****************************************************************************
00046  Mangle the 2nd name and check if it is then equal to the first name.
00047 ****************************************************************************/
00048 
00049 static BOOL mangled_equal(const char *name1, const char *name2,
00050                           const struct share_params *p)
00051 {
00052         pstring tmpname;
00053         
00054         pstrcpy(tmpname, name2);
00055         mangle_map(tmpname, True, False, p);
00056         return strequal(name1, tmpname);
00057 }
00058 
00059 /****************************************************************************
00060  Cope with the differing wildcard and non-wildcard error cases.
00061 ****************************************************************************/
00062 
00063 static NTSTATUS determine_path_error(const char *name, BOOL allow_wcard_last_component)
00064 {
00065         const char *p;
00066 
00067         if (!allow_wcard_last_component) {
00068                 /* Error code within a pathname. */
00069                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
00070         }
00071 
00072         /* We're terminating here so we
00073          * can be a little slower and get
00074          * the error code right. Windows
00075          * treats the last part of the pathname
00076          * separately I think, so if the last
00077          * component is a wildcard then we treat
00078          * this ./ as "end of component" */
00079 
00080         p = strchr(name, '/');
00081 
00082         if (!p && (ms_has_wild(name) || ISDOT(name))) {
00083                 /* Error code at the end of a pathname. */
00084                 return NT_STATUS_OBJECT_NAME_INVALID;
00085         } else {
00086                 /* Error code within a pathname. */
00087                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
00088         }
00089 }
00090         
00091 /****************************************************************************
00092 This routine is called to convert names from the dos namespace to unix
00093 namespace. It needs to handle any case conversions, mangling, format
00094 changes etc.
00095 
00096 We assume that we have already done a chdir() to the right "root" directory
00097 for this service.
00098 
00099 The function will return an NTSTATUS error if some part of the name except for the last
00100 part cannot be resolved, else NT_STATUS_OK.
00101 
00102 Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't
00103 get any fatal errors that should immediately terminate the calling
00104 SMB processing whilst resolving.
00105 
00106 If the saved_last_component != 0, then the unmodified last component
00107 of the pathname is returned there. This is used in an exceptional
00108 case in reply_mv (so far). If saved_last_component == 0 then nothing
00109 is returned there.
00110 
00111 If last_component_wcard is true then a MS wildcard was detected and
00112 should be allowed in the last component of the path only.
00113 
00114 On exit from unix_convert, if *pst was not null, then the file stat
00115 struct will be returned if the file exists and was found, if not this
00116 stat struct will be filled with zeros (and this can be detected by checking
00117 for nlinks = 0, which can never be true for any file).
00118 ****************************************************************************/
00119 
00120 NTSTATUS unix_convert(connection_struct *conn,
00121                         pstring name,
00122                         BOOL allow_wcard_last_component,
00123                         char *saved_last_component, 
00124                         SMB_STRUCT_STAT *pst)
00125 {
00126         SMB_STRUCT_STAT st;
00127         char *start, *end;
00128         pstring dirpath;
00129         pstring orig_path;
00130         BOOL component_was_mangled = False;
00131         BOOL name_has_wildcard = False;
00132 
00133         SET_STAT_INVALID(*pst);
00134 
00135         *dirpath = 0;
00136 
00137         if(saved_last_component) {
00138                 *saved_last_component = 0;
00139         }
00140 
00141         if (conn->printer) {
00142                 /* we don't ever use the filenames on a printer share as a
00143                         filename - so don't convert them */
00144                 return NT_STATUS_OK;
00145         }
00146 
00147         DEBUG(5, ("unix_convert called on file \"%s\"\n", name));
00148 
00149         /* 
00150          * Conversion to basic unix format is already done in check_path_syntax().
00151          */
00152 
00153         /* 
00154          * Names must be relative to the root of the service - any leading /.
00155          * and trailing /'s should have been trimmed by check_path_syntax().
00156          */
00157 
00158 #ifdef DEVELOPER
00159         SMB_ASSERT(*name != '/');
00160 #endif
00161 
00162         /*
00163          * If we trimmed down to a single '\0' character
00164          * then we should use the "." directory to avoid
00165          * searching the cache, but not if we are in a
00166          * printing share.
00167          * As we know this is valid we can return true here.
00168          */
00169 
00170         if (!*name) {
00171                 name[0] = '.';
00172                 name[1] = '\0';
00173                 if (SMB_VFS_STAT(conn,name,&st) == 0) {
00174                         *pst = st;
00175                 }
00176                 DEBUG(5,("conversion finished \"\" -> %s\n",name));
00177                 return NT_STATUS_OK;
00178         }
00179 
00180         if (name[0] == '.' && (name[1] == '/' || name[1] == '\0')) {
00181                 /* Start of pathname can't be "." only. */
00182                 if (name[1] == '\0' || name[2] == '\0') {
00183                         return NT_STATUS_OBJECT_NAME_INVALID;
00184                 } else {
00185                         return determine_path_error(&name[2], allow_wcard_last_component);
00186                 }
00187         }
00188 
00189         /*
00190          * Ensure saved_last_component is valid even if file exists.
00191          */
00192 
00193         if(saved_last_component) {
00194                 end = strrchr_m(name, '/');
00195                 if (end) {
00196                         pstrcpy(saved_last_component, end + 1);
00197                 } else {
00198                         pstrcpy(saved_last_component, name);
00199                 }
00200         }
00201 
00202         /*
00203          * Large directory fix normalization. If we're case sensitive, and
00204          * the case preserving parameters are set to "no", normalize the case of
00205          * the incoming filename from the client WHETHER IT EXISTS OR NOT !
00206          * This is in conflict with the current (3.0.20) man page, but is
00207          * what people expect from the "large directory howto". I'll update
00208          * the man page. Thanks to jht@samba.org for finding this. JRA.
00209          */
00210 
00211         if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) {
00212                 strnorm(name, lp_defaultcase(SNUM(conn)));
00213         }
00214         
00215         start = name;
00216         pstrcpy(orig_path, name);
00217 
00218         if(!conn->case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) {
00219                 *pst = st;
00220                 return NT_STATUS_OK;
00221         }
00222 
00223         /* 
00224          * stat the name - if it exists then we are all done!
00225          */
00226 
00227         if (SMB_VFS_STAT(conn,name,&st) == 0) {
00228                 /* Ensure we catch all names with in "/."
00229                    this is disallowed under Windows. */
00230                 const char *p = strstr(name, "/."); /* mb safe. */
00231                 if (p) {
00232                         if (p[2] == '/') {
00233                                 /* Error code within a pathname. */
00234                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
00235                         } else if (p[2] == '\0') {
00236                                 /* Error code at the end of a pathname. */
00237                                 return NT_STATUS_OBJECT_NAME_INVALID;
00238                         }
00239                 }
00240                 stat_cache_add(orig_path, name, conn->case_sensitive);
00241                 DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
00242                 *pst = st;
00243                 return NT_STATUS_OK;
00244         }
00245 
00246         DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start));
00247 
00248         /* 
00249          * A special case - if we don't have any mangling chars and are case
00250          * sensitive then searching won't help.
00251          */
00252 
00253         if (conn->case_sensitive && 
00254                         !mangle_is_mangled(name, conn->params) &&
00255                         !*lp_mangled_map(conn->params)) {
00256                 return NT_STATUS_OK;
00257         }
00258 
00259         /* 
00260          * is_mangled() was changed to look at an entire pathname, not 
00261          * just a component. JRA.
00262          */
00263 
00264         if (mangle_is_mangled(start, conn->params)) {
00265                 component_was_mangled = True;
00266         }
00267 
00268         /* 
00269          * Now we need to recursively match the name against the real 
00270          * directory structure.
00271          */
00272 
00273         /* 
00274          * Match each part of the path name separately, trying the names
00275          * as is first, then trying to scan the directory for matching names.
00276          */
00277 
00278         for (; start ; start = (end?end+1:(char *)NULL)) {
00279                 /* 
00280                  * Pinpoint the end of this section of the filename.
00281                  */
00282                 end = strchr(start, '/'); /* mb safe. '/' can't be in any encoded char. */
00283 
00284                 /* 
00285                  * Chop the name at this point.
00286                  */
00287                 if (end) {
00288                         *end = 0;
00289                 }
00290 
00291                 if (saved_last_component != 0) {
00292                         pstrcpy(saved_last_component, end ? end + 1 : start);
00293                 }
00294 
00295                 /* The name cannot have a component of "." */
00296 
00297                 if (ISDOT(start)) {
00298                         if (!end)  {
00299                                 /* Error code at the end of a pathname. */
00300                                 return NT_STATUS_OBJECT_NAME_INVALID;
00301                         }
00302                         return determine_path_error(end+1, allow_wcard_last_component);
00303                 }
00304 
00305                 /* The name cannot have a wildcard if it's not
00306                    the last component. */
00307 
00308                 name_has_wildcard = ms_has_wild(start);
00309 
00310                 /* Wildcard not valid anywhere. */
00311                 if (name_has_wildcard && !allow_wcard_last_component) {
00312                         return NT_STATUS_OBJECT_NAME_INVALID;
00313                 }
00314 
00315                 /* Wildcards never valid within a pathname. */
00316                 if (name_has_wildcard && end) {
00317                         return NT_STATUS_OBJECT_NAME_INVALID;
00318                 }
00319 
00320                 /* 
00321                  * Check if the name exists up to this point.
00322                  */
00323 
00324                 if (SMB_VFS_STAT(conn,name, &st) == 0) {
00325                         /*
00326                          * It exists. it must either be a directory or this must be
00327                          * the last part of the path for it to be OK.
00328                          */
00329                         if (end && !(st.st_mode & S_IFDIR)) {
00330                                 /*
00331                                  * An intermediate part of the name isn't a directory.
00332                                  */
00333                                 DEBUG(5,("Not a dir %s\n",start));
00334                                 *end = '/';
00335                                 /* 
00336                                  * We need to return the fact that the intermediate
00337                                  * name resolution failed. This is used to return an
00338                                  * error of ERRbadpath rather than ERRbadfile. Some
00339                                  * Windows applications depend on the difference between
00340                                  * these two errors.
00341                                  */
00342                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
00343                         }
00344 
00345                         if (!end) {
00346                                 /*
00347                                  * We just scanned for, and found the end of the path.
00348                                  * We must return the valid stat struct.
00349                                  * JRA.
00350                                  */
00351 
00352                                 *pst = st;
00353                         }
00354 
00355                 } else {
00356                         pstring rest;
00357 
00358                         /* Stat failed - ensure we don't use it. */
00359                         SET_STAT_INVALID(st);
00360                         *rest = 0;
00361 
00362                         /*
00363                          * Remember the rest of the pathname so it can be restored
00364                          * later.
00365                          */
00366 
00367                         if (end) {
00368                                 pstrcpy(rest,end+1);
00369                         }
00370 
00371                         /* Reset errno so we can detect directory open errors. */
00372                         errno = 0;
00373 
00374                         /*
00375                          * Try to find this part of the path in the directory.
00376                          */
00377 
00378                         if (name_has_wildcard || 
00379                             !scan_directory(conn, dirpath, start, sizeof(pstring) - 1 - (start - name))) {
00380                                 if (end) {
00381                                         /*
00382                                          * An intermediate part of the name can't be found.
00383                                          */
00384                                         DEBUG(5,("Intermediate not found %s\n",start));
00385                                         *end = '/';
00386 
00387                                         /* 
00388                                          * We need to return the fact that the intermediate
00389                                          * name resolution failed. This is used to return an
00390                                          * error of ERRbadpath rather than ERRbadfile. Some
00391                                          * Windows applications depend on the difference between
00392                                          * these two errors.
00393                                          */
00394 
00395                                         /* ENOENT, ENOTDIR and ELOOP all map to
00396                                          * NT_STATUS_OBJECT_PATH_NOT_FOUND
00397                                          * in the filename walk. */
00398 
00399                                         if (errno == ENOENT ||
00400                                                         errno == ENOTDIR ||
00401                                                         errno == ELOOP) {
00402                                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
00403                                         }
00404                                         return map_nt_error_from_unix(errno);
00405                                 }
00406 
00407                                 /* ENOENT is the only valid error here. */
00408                                 if ((errno != 0) && (errno != ENOENT) && (errno != EACCES)) {   
00409                     /* ENOTDIR and ELOOP both map to
00410                                          * NT_STATUS_OBJECT_PATH_NOT_FOUND
00411                                          * in the filename walk. */
00412                                         if (errno == ENOTDIR ||
00413                                                         errno == ELOOP) {
00414                                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
00415                                         }
00416                                         return map_nt_error_from_unix(errno);
00417                                 }
00418 
00419                                 /*
00420                                  * Just the last part of the name doesn't exist.
00421                                  * We need to strupper() or strlower() it as
00422                                  * this conversion may be used for file creation 
00423                                  * purposes. Fix inspired by Thomas Neumann <t.neumann@iku-ag.de>.
00424                                  */
00425                                 if (!conn->case_preserve ||
00426                                     (mangle_is_8_3(start, False, conn->params) &&
00427                                                  !conn->short_case_preserve)) {
00428                                         strnorm(start, lp_defaultcase(SNUM(conn)));
00429                                 }
00430 
00431                                 /*
00432                                  * check on the mangled stack to see if we can recover the 
00433                                  * base of the filename.
00434                                  */
00435 
00436                                 if (mangle_is_mangled(start, conn->params)) {
00437                                         mangle_check_cache( start, sizeof(pstring) - 1 - (start - name), conn->params);
00438                                 }
00439 
00440                                 DEBUG(5,("New file %s\n",start));
00441                                 return NT_STATUS_OK;
00442                         }
00443 
00444                         /* 
00445                          * Restore the rest of the string. If the string was mangled the size
00446                          * may have changed.
00447                          */
00448                         if (end) {
00449                                 end = start + strlen(start);
00450                                 if (!safe_strcat(start, "/", sizeof(pstring) - 1 - (start - name)) ||
00451                                     !safe_strcat(start, rest, sizeof(pstring) - 1 - (start - name))) {
00452                                         return map_nt_error_from_unix(ENAMETOOLONG);
00453                                 }
00454                                 *end = '\0';
00455                         } else {
00456                                 /*
00457                                  * We just scanned for, and found the end of the path.
00458                                  * We must return a valid stat struct if it exists.
00459                                  * JRA.
00460                                  */
00461 
00462                                 if (SMB_VFS_STAT(conn,name, &st) == 0) {
00463                                         *pst = st;
00464                                 } else {
00465                                         SET_STAT_INVALID(st);
00466                                 }
00467                         }
00468                 } /* end else */
00469 
00470 #ifdef DEVELOPER
00471                 if (VALID_STAT(st) && get_delete_on_close_flag(st.st_dev, st.st_ino)) {
00472                         return NT_STATUS_DELETE_PENDING;
00473                 }
00474 #endif
00475 
00476                 /* 
00477                  * Add to the dirpath that we have resolved so far.
00478                  */
00479                 if (*dirpath) {
00480                         pstrcat(dirpath,"/");
00481                 }
00482 
00483                 pstrcat(dirpath,start);
00484 
00485                 /*
00486                  * Don't cache a name with mangled or wildcard components
00487                  * as this can change the size.
00488                  */
00489                 
00490                 if(!component_was_mangled && !name_has_wildcard) {
00491                         stat_cache_add(orig_path, dirpath, conn->case_sensitive);
00492                 }
00493         
00494                 /* 
00495                  * Restore the / that we wiped out earlier.
00496                  */
00497                 if (end) {
00498                         *end = '/';
00499                 }
00500         }
00501   
00502         /*
00503          * Don't cache a name with mangled or wildcard components
00504          * as this can change the size.
00505          */
00506 
00507         if(!component_was_mangled && !name_has_wildcard) {
00508                 stat_cache_add(orig_path, name, conn->case_sensitive);
00509         }
00510 
00511         /* 
00512          * The name has been resolved.
00513          */
00514 
00515         DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
00516         return NT_STATUS_OK;
00517 }
00518 
00519 /****************************************************************************
00520  Check a filename - possibly caling reducename.
00521  This is called by every routine before it allows an operation on a filename.
00522  It does any final confirmation necessary to ensure that the filename is
00523  a valid one for the user to access.
00524 ****************************************************************************/
00525 
00526 NTSTATUS check_name(connection_struct *conn, const pstring name)
00527 {
00528         if (IS_VETO_PATH(conn, name))  {
00529                 /* Is it not dot or dot dot. */
00530                 if (!((name[0] == '.') && (!name[1] || (name[1] == '.' && !name[2])))) {
00531                         DEBUG(5,("check_name: file path name %s vetoed\n",name));
00532                         return map_nt_error_from_unix(ENOENT);
00533                 }
00534         }
00535 
00536         if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) {
00537                 NTSTATUS status = reduce_name(conn,name);
00538                 if (!NT_STATUS_IS_OK(status)) {
00539                         DEBUG(5,("check_name: name %s failed with %s\n",name, nt_errstr(status)));
00540                         return status;
00541                 }
00542         }
00543 
00544         return NT_STATUS_OK;
00545 }
00546 
00547 /****************************************************************************
00548  Scan a directory to find a filename, matching without case sensitivity.
00549  If the name looks like a mangled name then try via the mangling functions
00550 ****************************************************************************/
00551 
00552 static BOOL scan_directory(connection_struct *conn, const char *path, char *name, size_t maxlength)
00553 {
00554         struct smb_Dir *cur_dir;
00555         const char *dname;
00556         BOOL mangled;
00557         long curpos;
00558 
00559         mangled = mangle_is_mangled(name, conn->params);
00560 
00561         /* handle null paths */
00562         if (*path == 0)
00563                 path = ".";
00564 
00565         /*
00566          * The incoming name can be mangled, and if we de-mangle it
00567          * here it will not compare correctly against the filename (name2)
00568          * read from the directory and then mangled by the mangle_map()
00569          * call. We need to mangle both names or neither.
00570          * (JRA).
00571          *
00572          * Fix for bug found by Dina Fine. If in case sensitive mode then
00573          * the mangle cache is no good (3 letter extension could be wrong
00574          * case - so don't demangle in this case - leave as mangled and
00575          * allow the mangling of the directory entry read (which is done
00576          * case insensitively) to match instead. This will lead to more
00577          * false positive matches but we fail completely without it. JRA.
00578          */
00579 
00580         if (mangled && !conn->case_sensitive) {
00581                 mangled = !mangle_check_cache( name, maxlength, conn->params);
00582         }
00583 
00584         /* open the directory */
00585         if (!(cur_dir = OpenDir(conn, path, NULL, 0))) {
00586                 DEBUG(3,("scan dir didn't open dir [%s]\n",path));
00587                 return(False);
00588         }
00589 
00590         /* now scan for matching names */
00591         curpos = 0;
00592         while ((dname = ReadDirName(cur_dir, &curpos))) {
00593 
00594                 /* Is it dot or dot dot. */
00595                 if ((dname[0] == '.') && (!dname[1] || (dname[1] == '.' && !dname[2]))) {
00596                         continue;
00597                 }
00598 
00599                 /*
00600                  * At this point dname is the unmangled name.
00601                  * name is either mangled or not, depending on the state of the "mangled"
00602                  * variable. JRA.
00603                  */
00604 
00605                 /*
00606                  * Check mangled name against mangled name, or unmangled name
00607                  * against unmangled name.
00608                  */
00609 
00610                 if ((mangled && mangled_equal(name,dname,conn->params)) || fname_equal(name, dname, conn->case_sensitive)) {
00611                         /* we've found the file, change it's name and return */
00612                         safe_strcpy(name, dname, maxlength);
00613                         CloseDir(cur_dir);
00614                         return(True);
00615                 }
00616         }
00617 
00618         CloseDir(cur_dir);
00619         errno = ENOENT;
00620         return(False);
00621 }

Sambaに対してSat Aug 29 21:23:23 2009に生成されました。  doxygen 1.4.7