Commit b0446064 authored by William A. Rowe Jr's avatar William A. Rowe Jr
Browse files

  Commit this code before another patch becomes to difficult to follow.

  This patch does one thing, it changes the root path "/" to reflect an
  element count of Zero (0).  directory_walk will always accept the zero
  element (which sorts first, thankfully) on it's first go around.

  So, Unix will accept "/" when it's parsing it's first element "/".

  Dos/Win32 will accept "/" and "C:/" when they parse their first element,
  "C:/".  The root sorted first, so it behaves as users expect.

  The syntax "//" or "//machine" will be depreciated for now, the user
  needs to set up the extact "//machine/share/" that they want served
  on Win32.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90644 13f79535-47bb-0310-9956-ffa450edef68
parent 3d14a290
Loading
Loading
Loading
Loading
+24 −13
Original line number Diff line number Diff line
@@ -133,10 +133,19 @@ static void *create_core_dir_config(apr_pool_t *a, char *dir)
        conf->d = apr_pstrcat(a, dir, "/", NULL);
    }
    conf->d_is_fnmatch = conf->d ? (apr_is_fnmatch(conf->d) != 0) : 0;

    /* On all platforms, "/" is (at minimum) a faux root */
    conf->d_is_absolute = conf->d ? (ap_os_is_path_absolute(a, conf->d) 
                                      || (strcmp(conf->d, "/") == 0)) : 0;
    conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0;

    /* Make this explicit - the "/" root has 0 elements, that is, we
     * will always merge it, and it will always sort and merge first.
     * All others are sorted and tested by the number of slashes.
     */
    if (!conf->d || strcmp(conf->d, "/") == 0)
        conf->d_components = 0;
    else
        conf->d_components = ap_count_dirs(conf->d);

    conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL;
    conf->opts_add = conf->opts_remove = OPT_NONE;
@@ -1552,6 +1561,13 @@ static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)

    arg=apr_pstrndup(cmd->pool, arg, endp-arg);

    if (!arg) {
        if (thiscmd->cmd_data)
            return "<DirectoryMatch > block must specify a path";
        else
            return "<Directory > block must specify a path";
    }

    cmd->path = ap_getword_conf(cmd->pool, &arg);
    cmd->override = OR_ALL|ACCESS_CONF;

@@ -1560,27 +1576,22 @@ static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
    }
    else if (!strcmp(cmd->path, "~")) {
	cmd->path = ap_getword_conf(cmd->pool, &arg);
        if (!cmd->path) {
            return "<Directory ~ > block must specify a path";
	r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE);
    }
#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE)
    else if (strcmp(cmd->path, "/") == 0) {
        /* Treat 'default' path / as an inalienable root */
        /* Treat 'default' path "/" as the inalienable root */
        cmd->path = apr_pstrdup(cmd->pool, cmd->path);
    }
#endif
#if defined(HAVE_UNC_PATHS)
    else if (strcmp(cmd->path, "//") == 0) {
        /* Treat UNC path // as an inalienable root */
        cmd->path = apr_pstrdup(cmd->pool, cmd->path);
    }
#endif
    else {
        char *newpath;
	/* Ensure that the pathname is canonical */
        if (apr_filepath_merge(&newpath, NULL, cmd->path, 
                               APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS)
                               APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS) {
            return apr_pstrcat(cmd->pool, "<Directory \"", cmd->path,
			       "\"> is invalid.", NULL);
                               "\"> path is invalid.", NULL);
        }
        cmd->path = newpath;
    }

+44 −78
Original line number Diff line number Diff line
@@ -391,9 +391,7 @@ AP_DECLARE(int) directory_walk(request_rec *r)
    int res;
    unsigned i, num_dirs;
    int j, test_filename_len;
#if defined(HAVE_UNC_PATHS) || defined(NETWARE)
    unsigned iStart = 1;
#endif
    ap_conf_vector_t *entry_config;
    ap_conf_vector_t *this_conf;
    core_dir_config *entry_core;
@@ -555,27 +553,11 @@ AP_DECLARE(int) directory_walk(request_rec *r)
        iStart = 2;
#endif

#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE)
    /* Should match <Directory> sections starting from '/', not 'e:/' 
     * (for example).  WIN32/OS2/NETWARE do not have a single root directory,
     * they have one for each filesystem.  Traditionally, Apache has treated 
     * <Directory /> permissions as the base for the whole server, and this 
     * tradition should probably be preserved. 
     *
     * NOTE: MUST SYNC WITH ap_make_dirstr_prefix() CHANGE IN src/main/util.c
    /* i keeps track of how many segments we are testing
     * j keeps track of which section we're on, see core_reorder_directories 
     */
    if (test_filename[0] == '/')
        i = 1;
    else
        i = 0;
#else
    /* Normal File Systems are rooted at / */
    i = 1;
#endif /* def HAVE_DRIVE_LETTERS || NETWARE */

    /* j keeps track of which section we're on, see core_reorder_directories */
    j = 0;
    for (; i <= num_dirs; ++i) {
    for (i = 1; i <= num_dirs; ++i) {
        int overrides_here;
        core_dir_config *core_dir = ap_get_module_config(per_dir_defaults,
                                                         &core_module);
@@ -591,11 +573,8 @@ AP_DECLARE(int) directory_walk(request_rec *r)
         * permissions appropriate to the *parent* directory...
         */

#if defined(HAVE_UNC_PATHS) || defined(NETWARE)
        /* Test only legal names against the real filesystem */
        if (i >= iStart)
#endif
        if ((res = check_symlinks(test_dirname, core_dir->opts, r->pool))) {
        /* Test only real names (after the root) against the real filesystem */
        if ((i > iStart) && (res = check_symlinks(test_dirname, core_dir->opts, r->pool))) {
            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
                        "Symbolic link not allowed: %s", test_dirname);
            return res;
@@ -613,22 +592,19 @@ AP_DECLARE(int) directory_walk(request_rec *r)
            entry_core = ap_get_module_config(entry_config, &core_module);
            entry_dir = entry_core->d;

            if (entry_core->r
		|| !entry_core->d_is_absolute
#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE)
    /* To account for the top-level "/" directory when i == 0 
     * XXX: The net test may be wrong... may fail ap_os_is_path_absolute
     */
                || (entry_core->d_components > 1
                    && entry_core->d_components > i)
#else
                || entry_core->d_components > i
#endif /* def HAVE_DRIVE_LETTERS || NETWARE */
                )
            if (entry_core->r || !entry_core->d_is_absolute
                || entry_core->d_components > i)
                break;

            this_conf = NULL;
            if (entry_core->d_is_fnmatch) {
            /* We will always add in '0' element components, e.g. plain old
             * <Directory >, and <Directory "/"> is classified as zero 
             * so that Win32/Netware/OS2 etc all pick that up.
             */
            if (!entry_core->d_components) {
                this_conf = entry_config;
            }
            else if (entry_core->d_is_fnmatch) {
                if (!apr_fnmatch(entry_dir, test_dirname, FNM_PATHNAME)) {
                    this_conf = entry_config;
                }
@@ -643,25 +619,13 @@ AP_DECLARE(int) directory_walk(request_rec *r)
                core_dir = ap_get_module_config(per_dir_defaults,
                                                &core_module);
            }
#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE)
            /* So that other top-level directory sections (e.g. "e:/") aren't
             * skipped when i == 0
             * XXX: I don't get you here, Tim... That's a level 1 section, but
             *      we are at level 0. Did you mean fast-forward to the next?
             */
            else if (!i)
                break;
#endif /* def HAVE_DRIVE_LETTERS || NETWARE */
        }
        overrides_here = core_dir->override;

        /* If .htaccess files are enabled, check for one. */

#if defined(HAVE_UNC_PATHS) || defined(NETWARE)
        /* Test only legal names against the real filesystem */
        if (i >= iStart)
#endif
        if (overrides_here) {
        if ((i >= iStart) && overrides_here) {
            ap_conf_vector_t *htaccess_conf = NULL;

            res = ap_parse_htaccess(&htaccess_conf, r, overrides_here,
@@ -791,18 +755,17 @@ AP_DECLARE(int) directory_walk(request_rec *r)
        buf = apr_palloc(r->pool, buflen);
        strcpy (buf, r->filename);
        r->filename = buf;
    }
    else {
        return HTTP_FORBIDDEN;
    }
        r->finfo.valid = APR_FINFO_TYPE;
        r->finfo.filetype = APR_DIR; /* It's the root, of course it's a dir */
    }
    else {
        const char *entry_dir;

        /* Fake filenames (i.e. proxy:) only match Directory sections.
         */
    if (rv == APR_EBADPATH)
    {
        const char *entry_dir;
        if (rv != APR_EBADPATH)
            return HTTP_FORBIDDEN;
        }

        for (sec = 0; sec < num_sec; ++sec) {

@@ -842,7 +805,7 @@ AP_DECLARE(int) directory_walk(request_rec *r)
     * sec keeps track of which section we're on, since sections are
     *     ordered by number of segments. See core_reorder_directories 
     */
    seg = 1; 
    seg = ap_count_dirs(r->filename);
    sec = 0;
    do {
        int overrides_here;
@@ -851,41 +814,44 @@ AP_DECLARE(int) directory_walk(request_rec *r)
        
        /* We have no trailing slash, but we sure would appreciate one...
         */
        if (seg > 1)
        if (!sec && r->filename[strlen(r->filename)-1] != '/')
            strcat(r->filename, "/");

        /* Begin *this* level by looking for matching <Directory> sections
         * from the server config.
         */
        for (; sec < num_sec; ++sec) {
            char *entry_dir;
            const char *entry_dir;

            entry_config = sec_ent[sec];
            entry_core = ap_get_module_config(entry_config, &core_module);
            entry_dir = entry_core->d;

            /* No more possible matches? */
            /* No more possible matches for this many segments? 
             * We are done when we find relative/regex/longer components.
             */
            if (entry_core->r || !entry_core->d_is_absolute
                              || entry_core->d_components > seg)
                break;

            this_conf = NULL;
            if (entry_core->d_is_fnmatch) {
                if (!apr_fnmatch(entry_dir, r->filename, FNM_PATHNAME)) {
                    this_conf = entry_config;
                }
            /* We will never skip '0' element components, e.g. plain old
             * <Directory >, and <Directory "/"> are classified as zero 
             * so that Win32/Netware/OS2 etc all pick them up.
             * Otherwise, skip over the mismatches.
             */
            if (entry_core->d_components
                  && (entry_core->d_is_fnmatch
                        ? (apr_fnmatch(entry_dir, r->filename, FNM_PATHNAME) != APR_SUCCESS)
                        : (strcmp(r->filename, entry_dir) != 0)) {
                continue;
            }
            else if (!strcmp(r->filename, entry_dir))
                this_conf = entry_config;

            if (this_conf) {
            per_dir_defaults = ap_merge_per_dir_configs(r->pool,
                                                        per_dir_defaults,
                                                            this_conf);
                                                        entry_config);
            core_dir = ap_get_module_config(per_dir_defaults,
                                                &core_module);
        }
        }
        overrides_here = core_dir->override;

        /* If .htaccess files are enabled, check for one. */