util_win32.c revision 9d4ed8d865e29fdfe0e159e95eaa072a7242defb
2d2eda71267231c2526be701fe655db125852c1ffielding/* ====================================================================
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * The Apache Software License, Version 1.1
f062ed7bd262a37a909dd77ce5fc23b446818823fielding *
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Copyright (c) 2000 The Apache Software Foundation. All rights
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * reserved.
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * Redistribution and use in source and binary forms, with or without
2d2eda71267231c2526be701fe655db125852c1ffielding * modification, are permitted provided that the following conditions
2d2eda71267231c2526be701fe655db125852c1ffielding * are met:
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * 1. Redistributions of source code must retain the above copyright
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * notice, this list of conditions and the following disclaimer.
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * 2. Redistributions in binary form must reproduce the above copyright
2d2eda71267231c2526be701fe655db125852c1ffielding * notice, this list of conditions and the following disclaimer in
2d2eda71267231c2526be701fe655db125852c1ffielding * the documentation and/or other materials provided with the
2d2eda71267231c2526be701fe655db125852c1ffielding * distribution.
2d2eda71267231c2526be701fe655db125852c1ffielding *
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * 3. The end-user documentation included with the redistribution,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * if any, must include the following acknowledgment:
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * "This product includes software developed by the
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Apache Software Foundation (http://www.apache.org/)."
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Alternately, this acknowledgment may appear in the software itself,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * if and wherever such third-party acknowledgments normally appear.
2d2eda71267231c2526be701fe655db125852c1ffielding *
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * 4. The names "Apache" and "Apache Software Foundation" must
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * not be used to endorse or promote products derived from this
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * software without prior written permission. For written
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * permission, please contact apache@apache.org.
2d2eda71267231c2526be701fe655db125852c1ffielding *
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * 5. Products derived from this software may not be called "Apache",
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * nor may "Apache" appear in their name, without prior written
64185f9824e42f21ca7b9ae6c004484215c031a7rbb * permission of the Apache Software Foundation.
2d2eda71267231c2526be701fe655db125852c1ffielding *
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
2d2eda71267231c2526be701fe655db125852c1ffielding * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * SUCH DAMAGE.
2d2eda71267231c2526be701fe655db125852c1ffielding * ====================================================================
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * This software consists of voluntary contributions made by many
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * individuals on behalf of the Apache Software Foundation. For more
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * information on the Apache Software Foundation, please see
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * <http://www.apache.org/>.
2d2eda71267231c2526be701fe655db125852c1ffielding *
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * Portions of this software are based upon public domain software
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * originally written at the National Center for Supercomputing Applications,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding * University of Illinois, Urbana-Champaign.
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding#include "httpd.h"
2d2eda71267231c2526be701fe655db125852c1ffielding#include "http_log.h"
2d2eda71267231c2526be701fe655db125852c1ffielding#include "apr_strings.h"
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding#include <stdarg.h>
2d2eda71267231c2526be701fe655db125852c1ffielding#include <time.h>
2d2eda71267231c2526be701fe655db125852c1ffielding#include <stdlib.h>
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding/* Returns TRUE if the input string is a string
2d2eda71267231c2526be701fe655db125852c1ffielding * of one or more '.' characters.
2d2eda71267231c2526be701fe655db125852c1ffielding */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbstatic BOOL OnlyDots(char *pString)
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb{
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb char *c;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (*pString == '\0')
2d2eda71267231c2526be701fe655db125852c1ffielding return FALSE;
30c289e6bc6d28d210b21edd800ab2cfc78a8381wrowe
bd53cb2bf4d77574fd502e1c02d8c3c0d5431967stoddard for (c = pString;*c;c++)
b4c8a80f7dbfc9b56dbe03bdc28f0b5eb5f23697rbb if (*c != '.')
b4c8a80f7dbfc9b56dbe03bdc28f0b5eb5f23697rbb return FALSE;
44c46ef733836b32585d135d2d90856e7cfd9929rbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb return TRUE;
2d2eda71267231c2526be701fe655db125852c1ffielding}
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb/* Accepts as input a pathname, and tries to match it to an
14bea4ba98aabaf554e37165a07123bb05d6736bstoddard * existing path and return the pathname in the case that
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * is present on the existing path. This routine also
9731f9232bddd7dbac757c780b2b1a2a6931dce7stoddard * converts alias names to long names.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbAP_DECLARE(char *) ap_os_systemcase_filename(apr_pool_t *pPool,
2d2eda71267231c2526be701fe655db125852c1ffielding const char *szFile)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding char buf[HUGE_STRING_LEN];
2d2eda71267231c2526be701fe655db125852c1ffielding char *pInputName;
2d2eda71267231c2526be701fe655db125852c1ffielding char *p, *q, *t;
2d2eda71267231c2526be701fe655db125852c1ffielding BOOL bDone = FALSE;
2d2eda71267231c2526be701fe655db125852c1ffielding BOOL bFileExists = TRUE;
2d2eda71267231c2526be701fe655db125852c1ffielding HANDLE hFind;
2d2eda71267231c2526be701fe655db125852c1ffielding WIN32_FIND_DATA wfd;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (!szFile || strlen(szFile) == 0 || strlen(szFile) >= sizeof(buf))
2d2eda71267231c2526be701fe655db125852c1ffielding return apr_pstrdup(pPool, "");
2d2eda71267231c2526be701fe655db125852c1ffielding
2e123e8beedc9f921448c113e2d6823a92fd5261fielding t = buf;
2e123e8beedc9f921448c113e2d6823a92fd5261fielding pInputName = apr_pstrdup(pPool, szFile);
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* First convert all slashes to \ so Win32 calls work OK */
2d2eda71267231c2526be701fe655db125852c1ffielding for (p = pInputName; *p; p++) {
2d2eda71267231c2526be701fe655db125852c1ffielding if (*p == '/')
2d2eda71267231c2526be701fe655db125852c1ffielding *p = '\\';
2d2eda71267231c2526be701fe655db125852c1ffielding }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb q = p = pInputName;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* If there is drive information, copy it over. */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (pInputName[1] == ':') {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* This is correct - if systemcase is used for
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * comparison, d: designations will match
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb *(t++) = tolower(*p++);
2d2eda71267231c2526be701fe655db125852c1ffielding *(t++) = *p++;
2d2eda71267231c2526be701fe655db125852c1ffielding q = p;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* If all we have is a drive letter, then we are done */
2d2eda71267231c2526be701fe655db125852c1ffielding if (!*p)
2d2eda71267231c2526be701fe655db125852c1ffielding bDone = TRUE;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding q = p;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (*p == '\\') {
2d2eda71267231c2526be701fe655db125852c1ffielding ++p;
2d2eda71267231c2526be701fe655db125852c1ffielding if (*p == '\\') /* UNC name */
2d2eda71267231c2526be701fe655db125852c1ffielding {
2d2eda71267231c2526be701fe655db125852c1ffielding p++;
2d2eda71267231c2526be701fe655db125852c1ffielding /* Get past the machine name. FindFirstFile
2d2eda71267231c2526be701fe655db125852c1ffielding * will not find a machine name only
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding *(t++) = '\\';
2d2eda71267231c2526be701fe655db125852c1ffielding ++q;
2d2eda71267231c2526be701fe655db125852c1ffielding p = strchr(p + 1, '\\');
2d2eda71267231c2526be701fe655db125852c1ffielding if (p)
2d2eda71267231c2526be701fe655db125852c1ffielding {
2d2eda71267231c2526be701fe655db125852c1ffielding p++;
2d2eda71267231c2526be701fe655db125852c1ffielding /* Get past the share name. FindFirstFile */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* will not find a \\machine\share name only */
2d2eda71267231c2526be701fe655db125852c1ffielding p = strchr(p, '\\');
2d2eda71267231c2526be701fe655db125852c1ffielding if (p) {
2d2eda71267231c2526be701fe655db125852c1ffielding /* This was faulty - as of 1.3.13 \\machine\share
2d2eda71267231c2526be701fe655db125852c1ffielding * name is now always lowercased
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding strncpy(t,q,p-q);
2d2eda71267231c2526be701fe655db125852c1ffielding strlwr(t);
2d2eda71267231c2526be701fe655db125852c1ffielding t += p - q;
2d2eda71267231c2526be701fe655db125852c1ffielding q = p;
2d2eda71267231c2526be701fe655db125852c1ffielding p++;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (!p) {
2d2eda71267231c2526be701fe655db125852c1ffielding bFileExists = FALSE;
2d2eda71267231c2526be701fe655db125852c1ffielding p = q;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding p = strchr(p, '\\');
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding while (!bDone) {
2d2eda71267231c2526be701fe655db125852c1ffielding if (p)
2d2eda71267231c2526be701fe655db125852c1ffielding *p = '\0';
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (strchr(q, '*') || strchr(q, '?'))
2d2eda71267231c2526be701fe655db125852c1ffielding bFileExists = FALSE;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* If the path exists so far, call FindFirstFile
2d2eda71267231c2526be701fe655db125852c1ffielding * again. However, if this portion of the path contains
2d2eda71267231c2526be701fe655db125852c1ffielding * only '.' charaters, skip the call to FindFirstFile
2d2eda71267231c2526be701fe655db125852c1ffielding * since it will convert '.' and '..' to actual names.
2d2eda71267231c2526be701fe655db125852c1ffielding * Note: in the call to OnlyDots, we may have to skip
2d2eda71267231c2526be701fe655db125852c1ffielding * a leading slash.
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding if (bFileExists && !OnlyDots((*q == '.' ? q : q+1))) {
2d2eda71267231c2526be701fe655db125852c1ffielding hFind = FindFirstFile(pInputName, &wfd);
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (hFind == INVALID_HANDLE_VALUE) {
2d2eda71267231c2526be701fe655db125852c1ffielding bFileExists = FALSE;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding else {
2d2eda71267231c2526be701fe655db125852c1ffielding FindClose(hFind);
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (*q == '\\')
2d2eda71267231c2526be701fe655db125852c1ffielding *(t++) = '\\';
2d2eda71267231c2526be701fe655db125852c1ffielding t = strchr(strcpy(t, wfd.cFileName), '\0');
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (!bFileExists || OnlyDots((*q == '.' ? q : q+1))) {
2d2eda71267231c2526be701fe655db125852c1ffielding /* XXX: Comparison could be faulty ...\unknown
2d2eda71267231c2526be701fe655db125852c1ffielding * names may not be tested (if they reside outside
2d2eda71267231c2526be701fe655db125852c1ffielding * of the file system)!
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding strcpy(t, q);
2d2eda71267231c2526be701fe655db125852c1ffielding t = strchr(t, '\0');
2e123e8beedc9f921448c113e2d6823a92fd5261fielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (p) {
2d2eda71267231c2526be701fe655db125852c1ffielding q = p;
2d2eda71267231c2526be701fe655db125852c1ffielding *p++ = '\\';
2e123e8beedc9f921448c113e2d6823a92fd5261fielding p = strchr(p, '\\');
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding else {
2d2eda71267231c2526be701fe655db125852c1ffielding bDone = TRUE;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding *t = '\0';
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Finally, convert all slashes to / so server code handles it ok */
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding for (p = buf; *p; p++) {
2d2eda71267231c2526be701fe655db125852c1ffielding if (*p == '\\')
2d2eda71267231c2526be701fe655db125852c1ffielding *p = '/';
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding return apr_pstrdup(pPool, buf);
2d2eda71267231c2526be701fe655db125852c1ffielding}
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding/* Perform canonicalization with the exception that the
2d2eda71267231c2526be701fe655db125852c1ffielding * input case is preserved.
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffieldingAP_DECLARE(char *) ap_os_case_canonical_filename(apr_pool_t *pPool,
2d2eda71267231c2526be701fe655db125852c1ffielding const char *szFile)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding char *pNewStr;
2d2eda71267231c2526be701fe655db125852c1ffielding char *s;
2d2eda71267231c2526be701fe655db125852c1ffielding char *p;
2d2eda71267231c2526be701fe655db125852c1ffielding char *q;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (szFile == NULL || strlen(szFile) == 0)
2d2eda71267231c2526be701fe655db125852c1ffielding return apr_pstrdup(pPool, "");
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding pNewStr = apr_pstrdup(pPool, szFile);
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Change all '\' characters to '/' characters.
2d2eda71267231c2526be701fe655db125852c1ffielding * While doing this, remove any trailing '.'.
2d2eda71267231c2526be701fe655db125852c1ffielding * Also, blow away any directories with 3 or
2d2eda71267231c2526be701fe655db125852c1ffielding * more '.'
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding for (p = pNewStr,s = pNewStr; *s; s++,p++) {
2d2eda71267231c2526be701fe655db125852c1ffielding if (*s == '\\' || *s == '/') {
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding q = p;
2d2eda71267231c2526be701fe655db125852c1ffielding while (p > pNewStr && *(p-1) == '.')
2d2eda71267231c2526be701fe655db125852c1ffielding p--;
2d2eda71267231c2526be701fe655db125852c1ffielding
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet if (p == pNewStr && q-p <= 2 && *p == '.')
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet p = q;
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet else if (p > pNewStr && p < q && *(p-1) == '/') {
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet if (q-p > 2)
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet p--;
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet else
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet p = q;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding *p = '/';
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding else {
2d2eda71267231c2526be701fe655db125852c1ffielding *p = *s;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding *p = '\0';
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Blow away any final trailing '.' since on Win32
2d2eda71267231c2526be701fe655db125852c1ffielding * foo.bat == foo.bat. == foo.bat... etc.
2d2eda71267231c2526be701fe655db125852c1ffielding * Also blow away any trailing spaces since
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * "filename" == "filename "
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb q = p;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb while (p > pNewStr && (*(p-1) == '.' || *(p-1) == ' '))
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb p--;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if ((p > pNewStr) ||
32644678e889a3253f71bde0b3d6daea6d9dc21awrowe (p == pNewStr && q-p > 2))
32644678e889a3253f71bde0b3d6daea6d9dc21awrowe *p = '\0';
58ce9fee5e23441391d64ad064268bd9d1f2d056ask
32644678e889a3253f71bde0b3d6daea6d9dc21awrowe
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* One more security issue to deal with. Win32 allows
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * you to create long filenames. However, alias filenames
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * are always created so that the filename will
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * conform to 8.3 rules. According to the Microsoft
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * Developer's network CD (1/98)
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * "Automatically generated aliases are composed of the
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * first six characters of the filename plus ~n
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * (where n is a number) and the first three characters
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * after the last period."
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * Here, we attempt to detect and decode these names.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb *
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * XXX: Netware network clients may have alternate short names,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * simply truncated, with no embedded '~'. Further, this behavior
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * can be modified on WinNT volumes. This was not a safe test,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * therefore exclude the '~' pretest.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb#ifdef WIN32_SHORT_FILENAME_INSECURE_BEHAVIOR
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb p = strchr(pNewStr, '~');
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (p != NULL)
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb#endif
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb char *pConvertedName, *pQstr, *pPstr;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb char buf[HUGE_STRING_LEN];
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* We potentially have a short name. Call
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * ap_os_systemcase_filename to examine the filesystem
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * and possibly extract the long name.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb pConvertedName = ap_os_systemcase_filename(pPool, pNewStr);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* Since we want to preserve the incoming case as much
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * as we can, compare for differences in the string and
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * only substitute in the path names that changed.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (stricmp(pNewStr, pConvertedName)) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb buf[0] = '\0';
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb q = pQstr = pConvertedName;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb p = pPstr = pNewStr;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb do {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb q = strchr(q,'/');
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb p = strchr(p,'/');
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (p != NULL) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb *q = '\0';
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb *p = '\0';
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (stricmp(pQstr, pPstr))
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb strcat(buf, pQstr); /* Converted name */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb else
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb strcat(buf, pPstr); /* Original name */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (p != NULL) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb pQstr = q;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb pPstr = p;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb *q++ = '/';
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb *p++ = '/';
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb } while (p != NULL);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb pNewStr = apr_pstrdup(pPool, buf);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb return pNewStr;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb}
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb/* Perform complete canonicalization.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbAP_DECLARE(char *) ap_os_canonical_filename(apr_pool_t *pPool, const char *szFile)
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb{
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb char *pNewName;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb pNewName = ap_os_case_canonical_filename(pPool, szFile);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb strlwr(pNewName);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb return pNewName;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb}
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb/*
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * ap_os_is_filename_valid is given a filename, and returns 0 if the filename
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * is not valid for use on this system. On Windows, this means it fails any
2e123e8beedc9f921448c113e2d6823a92fd5261fielding * of the tests below. Otherwise returns 1.
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * Test for filename validity on Win32. This is of tests come in part from
2d2eda71267231c2526be701fe655db125852c1ffielding * the MSDN article at "Technical Articles, Windows Platform, Base Services,
9ecf4c650535acf4d966f102e665af79ec97c01arbb * Guidelines, Making Room for Long Filenames" although the information
9ecf4c650535acf4d966f102e665af79ec97c01arbb * in MSDN about filename testing is incomplete or conflicting. There is a
2d2eda71267231c2526be701fe655db125852c1ffielding * similar set of tests in "Technical Articles, Windows Platform, Base Services,
2d2eda71267231c2526be701fe655db125852c1ffielding * Guidelines, Moving Unix Applications to Windows NT".
2d2eda71267231c2526be701fe655db125852c1ffielding *
2e47849164eb31bd63f629b952f7ccc9a5ed19afrbb * The tests are:
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * 1) total path length greater than MAX_PATH
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * 2) anything using the octets 0-31 or characters " < > | :
2d2eda71267231c2526be701fe655db125852c1ffielding * (these are reserved for Windows use in filenames. In addition
2d2eda71267231c2526be701fe655db125852c1ffielding * each file system has its own additional characters that are
58ce9fee5e23441391d64ad064268bd9d1f2d056ask * invalid. See KB article Q100108 for more details).
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * 3) anything ending in "." (no matter how many)
2d2eda71267231c2526be701fe655db125852c1ffielding * (filename doc, doc. and doc... all refer to the same file)
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * 4) any segment in which the basename (before first period) matches
2d2eda71267231c2526be701fe655db125852c1ffielding * one of the DOS device names
7463de0c603f07c9e1820e812d2f1a73661843e6rbb * (the list comes from KB article Q100108 although some people
2d2eda71267231c2526be701fe655db125852c1ffielding * reports that additional names such as "COM5" are also special
2d2eda71267231c2526be701fe655db125852c1ffielding * devices).
2d2eda71267231c2526be701fe655db125852c1ffielding *
2d2eda71267231c2526be701fe655db125852c1ffielding * If the path fails ANY of these tests, the result must be to deny access.
2d2eda71267231c2526be701fe655db125852c1ffielding */
b4c8a80f7dbfc9b56dbe03bdc28f0b5eb5f23697rbb
2d2eda71267231c2526be701fe655db125852c1ffieldingAP_DECLARE(int) ap_os_is_filename_valid(const char *file)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding const char *segstart;
2d2eda71267231c2526be701fe655db125852c1ffielding unsigned int seglength;
2d2eda71267231c2526be701fe655db125852c1ffielding const char *pos;
2d2eda71267231c2526be701fe655db125852c1ffielding static const char * const invalid_characters = "?\"<>*|:";
2d2eda71267231c2526be701fe655db125852c1ffielding static const char * const invalid_filenames[] = {
2d2eda71267231c2526be701fe655db125852c1ffielding "CON", "AUX", "COM1", "COM2", "COM3",
2d2eda71267231c2526be701fe655db125852c1ffielding "COM4", "LPT1", "LPT2", "LPT3", "PRN", "NUL", NULL
2d2eda71267231c2526be701fe655db125852c1ffielding };
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Test 1 */
2d2eda71267231c2526be701fe655db125852c1ffielding if (strlen(file) >= MAX_PATH) {
2d2eda71267231c2526be701fe655db125852c1ffielding /* Path too long for Windows. Note that this test is not valid
2d2eda71267231c2526be701fe655db125852c1ffielding * if the path starts with //?/ or \\?\. */
2d2eda71267231c2526be701fe655db125852c1ffielding return 0;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding pos = file;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Skip any leading non-path components. This can be either a
2d2eda71267231c2526be701fe655db125852c1ffielding * drive letter such as C:, or a UNC path such as \\SERVER\SHARE\.
2d2eda71267231c2526be701fe655db125852c1ffielding * We continue and check the rest of the path based on the rules above.
2d2eda71267231c2526be701fe655db125852c1ffielding * This means we could eliminate valid filenames from servers which
2d2eda71267231c2526be701fe655db125852c1ffielding * are not running NT (such as Samba).
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (pos[0] && pos[1] == ':') {
2d2eda71267231c2526be701fe655db125852c1ffielding /* Skip leading drive letter */
2d2eda71267231c2526be701fe655db125852c1ffielding pos += 2;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding else {
2d2eda71267231c2526be701fe655db125852c1ffielding if ((pos[0] == '\\' || pos[0] == '/') &&
2d2eda71267231c2526be701fe655db125852c1ffielding (pos[1] == '\\' || pos[1] == '/')) {
2d2eda71267231c2526be701fe655db125852c1ffielding /* Is a UNC, so skip the server name and share name */
2d2eda71267231c2526be701fe655db125852c1ffielding pos += 2;
2d2eda71267231c2526be701fe655db125852c1ffielding while (*pos && *pos != '/' && *pos != '\\')
2d2eda71267231c2526be701fe655db125852c1ffielding pos++;
2d2eda71267231c2526be701fe655db125852c1ffielding if (!*pos) {
2d2eda71267231c2526be701fe655db125852c1ffielding /* No share name */
2d2eda71267231c2526be701fe655db125852c1ffielding return 0;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding pos++; /* Move to start of share name */
2d2eda71267231c2526be701fe655db125852c1ffielding while (*pos && *pos != '/' && *pos != '\\')
2d2eda71267231c2526be701fe655db125852c1ffielding pos++;
2d2eda71267231c2526be701fe655db125852c1ffielding if (!*pos) {
2d2eda71267231c2526be701fe655db125852c1ffielding /* No path information */
2d2eda71267231c2526be701fe655db125852c1ffielding return 0;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding while (*pos) {
2d2eda71267231c2526be701fe655db125852c1ffielding unsigned int idx;
2d2eda71267231c2526be701fe655db125852c1ffielding unsigned int baselength;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding while (*pos == '/' || *pos == '\\') {
2d2eda71267231c2526be701fe655db125852c1ffielding pos++;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (*pos == '\0') {
2d2eda71267231c2526be701fe655db125852c1ffielding break;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding segstart = pos; /* start of segment */
2d2eda71267231c2526be701fe655db125852c1ffielding while (*pos && *pos != '/' && *pos != '\\') {
2d2eda71267231c2526be701fe655db125852c1ffielding pos++;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding seglength = pos - segstart;
2d2eda71267231c2526be701fe655db125852c1ffielding /*
2d2eda71267231c2526be701fe655db125852c1ffielding * Now we have a segment of the path, starting at position "segstart"
2d2eda71267231c2526be701fe655db125852c1ffielding * and length "seglength"
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Test 2 */
2d2eda71267231c2526be701fe655db125852c1ffielding for (idx = 0; idx < seglength; idx++) {
2d2eda71267231c2526be701fe655db125852c1ffielding if ((segstart[idx] > 0 && segstart[idx] < 32) ||
2d2eda71267231c2526be701fe655db125852c1ffielding strchr(invalid_characters, segstart[idx])) {
2d2eda71267231c2526be701fe655db125852c1ffielding return 0;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Test 3 */
2d2eda71267231c2526be701fe655db125852c1ffielding if (segstart[seglength-1] == '.') {
2d2eda71267231c2526be701fe655db125852c1ffielding return 0;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* Test 4 */
2d2eda71267231c2526be701fe655db125852c1ffielding for (baselength = 0; baselength < seglength; baselength++) {
2d2eda71267231c2526be701fe655db125852c1ffielding if (segstart[baselength] == '.') {
2d2eda71267231c2526be701fe655db125852c1ffielding break;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* baselength is the number of characters in the base path of
2d2eda71267231c2526be701fe655db125852c1ffielding * the segment (which could be the same as the whole segment length,
2d2eda71267231c2526be701fe655db125852c1ffielding * if it does not include any dot characters). */
2d2eda71267231c2526be701fe655db125852c1ffielding if (baselength == 3 || baselength == 4) {
2d2eda71267231c2526be701fe655db125852c1ffielding for (idx = 0; invalid_filenames[idx]; idx++) {
2d2eda71267231c2526be701fe655db125852c1ffielding if (strlen(invalid_filenames[idx]) == baselength &&
2d2eda71267231c2526be701fe655db125852c1ffielding !strnicmp(invalid_filenames[idx], segstart, baselength)) {
2d2eda71267231c2526be701fe655db125852c1ffielding return 0;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding return 1;
2d2eda71267231c2526be701fe655db125852c1ffielding}
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingAP_DECLARE(apr_status_t) ap_os_create_privileged_process(const request_rec *r,
2d2eda71267231c2526be701fe655db125852c1ffielding apr_proc_t *newproc, const char *progname,
2d2eda71267231c2526be701fe655db125852c1ffielding char *const *args, char **env,
2d2eda71267231c2526be701fe655db125852c1ffielding apr_procattr_t *attr, apr_pool_t *p)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding return APR_ENOTIMPL;
2d2eda71267231c2526be701fe655db125852c1ffielding}
54e94821097724bf413d2d4cc70711760f7494e1trawick
54e94821097724bf413d2d4cc70711760f7494e1trawick