Ejemplo n.º 1
0
/* {{{ expand_filepath_use_realpath
 */
PHPAPI char *expand_filepath_with_mode(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len, int realpath_mode)
{
	cwd_state new_state;
	char cwd[MAXPATHLEN];
	int copy_len;
	int path_len;

	if (!filepath[0]) {
		return NULL;
	}

	path_len = (int)strlen(filepath);

	if (IS_ABSOLUTE_PATH(filepath, path_len)) {
		cwd[0] = '\0';
	} else {
		const char *iam = SG(request_info).path_translated;
		const char *result;
		if (relative_to) {
			if (relative_to_len > MAXPATHLEN-1U) {
				return NULL;
			}
			result = relative_to;
			memcpy(cwd, relative_to, relative_to_len+1U);
		} else {
			result = VCWD_GETCWD(cwd, MAXPATHLEN);
		}

		if (!result && (iam != filepath)) {
			int fdtest = -1;

			fdtest = VCWD_OPEN(filepath, O_RDONLY);
			if (fdtest != -1) {
				/* return a relative file path if for any reason
				 * we cannot cannot getcwd() and the requested,
				 * relatively referenced file is accessible */
				copy_len = path_len > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : path_len;
				if (real_path) {
					memcpy(real_path, filepath, copy_len);
					real_path[copy_len] = '\0';
				} else {
					real_path = estrndup(filepath, copy_len);
				}
				close(fdtest);
				return real_path;
			} else {
				cwd[0] = '\0';
			}
		} else if (!result) {
			cwd[0] = '\0';
		}
	}

	new_state.cwd = estrdup(cwd);
	new_state.cwd_length = (int)strlen(cwd);

	if (virtual_file_ex(&new_state, filepath, NULL, realpath_mode)) {
		efree(new_state.cwd);
		return NULL;
	}

	if (real_path) {
		copy_len = new_state.cwd_length > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : new_state.cwd_length;
		memcpy(real_path, new_state.cwd, copy_len);
		real_path[copy_len] = '\0';
	} else {
		real_path = estrndup(new_state.cwd, new_state.cwd_length);
	}
	efree(new_state.cwd);

	return real_path;
}
Ejemplo n.º 2
0
/* {{{ php_check_specific_open_basedir
	When open_basedir is not NULL, check if the given filename is located in
	open_basedir. Returns -1 if error or not in the open_basedir, else 0.
	When open_basedir is NULL, always return 0.
*/
PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path)
{
	char resolved_name[MAXPATHLEN];
	char resolved_basedir[MAXPATHLEN];
	char local_open_basedir[MAXPATHLEN];
	char path_tmp[MAXPATHLEN];
	char *path_file;
	int resolved_basedir_len;
	int resolved_name_len;
	size_t path_len;
	int nesting_level = 0;

	/* Special case basedir==".": Use script-directory */
	if (strcmp(basedir, ".") || !VCWD_GETCWD(local_open_basedir, MAXPATHLEN)) {
		/* Else use the unmodified path */
		strlcpy(local_open_basedir, basedir, sizeof(local_open_basedir));
	}

	path_len = strlen(path);
	if (path_len > (MAXPATHLEN - 1)) {
		/* empty and too long paths are invalid */
		return -1;
	}

	/* normalize and expand path */
	if (expand_filepath(path, resolved_name) == NULL) {
		return -1;
	}

	path_len = strlen(resolved_name);
	memcpy(path_tmp, resolved_name, path_len + 1); /* safe */

	while (VCWD_REALPATH(path_tmp, resolved_name) == NULL) {
#if defined(PHP_WIN32) || defined(HAVE_SYMLINK)
		if (nesting_level == 0) {
			int ret;
			char buf[MAXPATHLEN];

			ret = php_sys_readlink(path_tmp, buf, MAXPATHLEN - 1);
			if (ret < 0) {
				/* not a broken symlink, move along.. */
			} else {
				/* put the real path into the path buffer */
				memcpy(path_tmp, buf, ret);
				path_tmp[ret] = '\0';
			}
		}
#endif

#ifdef PHP_WIN32
		path_file = strrchr(path_tmp, DEFAULT_SLASH);
		if (!path_file) {
			path_file = strrchr(path_tmp, '/');
		}
#else
		path_file = strrchr(path_tmp, DEFAULT_SLASH);
#endif
		if (!path_file) {
			/* none of the path components exist. definitely not in open_basedir.. */
			return -1;
		} else {
			path_len = path_file - path_tmp + 1;
#ifdef PHP_WIN32
			if (path_len > 1 && path_tmp[path_len - 2] == ':') {
				if (path_len != 3) {
					return -1;
				}
				/* this is c:\ */
				path_tmp[path_len] = '\0';
			} else {
				path_tmp[path_len - 1] = '\0';
			}
#else
			path_tmp[path_len - 1] = '\0';
#endif
		}
		nesting_level++;
	}

	/* Resolve open_basedir to resolved_basedir */
	if (expand_filepath(local_open_basedir, resolved_basedir) != NULL) {
		int basedir_len = (int)strlen(basedir);
		/* Handler for basedirs that end with a / */
		resolved_basedir_len = (int)strlen(resolved_basedir);
#ifdef PHP_WIN32
		if (basedir[basedir_len - 1] == PHP_DIR_SEPARATOR || basedir[basedir_len - 1] == '/') {
#else
		if (basedir[basedir_len - 1] == PHP_DIR_SEPARATOR) {
#endif
			if (resolved_basedir[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
				resolved_basedir[resolved_basedir_len] = PHP_DIR_SEPARATOR;
				resolved_basedir[++resolved_basedir_len] = '\0';
			}
		} else {
				resolved_basedir[resolved_basedir_len++] = PHP_DIR_SEPARATOR;
				resolved_basedir[resolved_basedir_len] = '\0';
		}

		resolved_name_len = (int)strlen(resolved_name);
		if (path_tmp[path_len - 1] == PHP_DIR_SEPARATOR) {
			if (resolved_name[resolved_name_len - 1] != PHP_DIR_SEPARATOR) {
				resolved_name[resolved_name_len] = PHP_DIR_SEPARATOR;
				resolved_name[++resolved_name_len] = '\0';
			}
		}

		/* Check the path */
#ifdef PHP_WIN32
		if (strncasecmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
#else
		if (strncmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
#endif
			if (resolved_name_len > resolved_basedir_len &&
				resolved_name[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
				return -1;
			} else {
				/* File is in the right directory */
				return 0;
			}
		} else {
			/* /openbasedir/ and /openbasedir are the same directory */
			if (resolved_basedir_len == (resolved_name_len + 1) && resolved_basedir[resolved_basedir_len - 1] == PHP_DIR_SEPARATOR) {
#ifdef PHP_WIN32
				if (strncasecmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
#else
				if (strncmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
#endif
					return 0;
				}
			}
			return -1;
		}
	} else {
		/* Unable to resolve the real path, return -1 */
		return -1;
	}
}
/* }}} */

PHPAPI int php_check_open_basedir(const char *path)
{
	return php_check_open_basedir_ex(path, 1);
}

/* {{{ php_check_open_basedir
 */
PHPAPI int php_check_open_basedir_ex(const char *path, int warn)
{
	/* Only check when open_basedir is available */
	if (PG(open_basedir) && *PG(open_basedir)) {
		char *pathbuf;
		char *ptr;
		char *end;

		/* Check if the path is too long so we can give a more useful error
		* message. */
		if (strlen(path) > (MAXPATHLEN - 1)) {
			php_error_docref(NULL, E_WARNING, "File name is longer than the maximum allowed path length on this platform (%d): %s", MAXPATHLEN, path);
			errno = EINVAL;
			return -1;
		}

		pathbuf = estrdup(PG(open_basedir));

		ptr = pathbuf;

		while (ptr && *ptr) {
			end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
			if (end != NULL) {
				*end = '\0';
				end++;
			}

			if (php_check_specific_open_basedir(ptr, path) == 0) {
				efree(pathbuf);
				return 0;
			}

			ptr = end;
		}
		if (warn) {
			php_error_docref(NULL, E_WARNING, "open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s)", path, PG(open_basedir));
		}
		efree(pathbuf);
		errno = EPERM; /* we deny permission to open it */
		return -1;
	}

	/* Nothing to check... */
	return 0;
}
/* }}} */

/* {{{ php_fopen_and_set_opened_path
 */
static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, zend_string **opened_path)
{
	FILE *fp;

	if (php_check_open_basedir((char *)path)) {
		return NULL;
	}
	fp = VCWD_FOPEN(path, mode);
	if (fp && opened_path) {
		//TODO :avoid reallocation
		char *tmp = expand_filepath_with_mode(path, NULL, NULL, 0, CWD_EXPAND);
		if (tmp) {
			*opened_path = zend_string_init(tmp, strlen(tmp), 0);
			efree(tmp);
		}
	}
	return fp;
}
Ejemplo n.º 3
0
/* {{{ proto boolean XMLReader::XML(string source [, string encoding [, int options]])
Sets the string that the XMLReader will parse. */
PHP_METHOD(xmlreader, XML)
{
	zval *id;
	size_t source_len = 0, encoding_len = 0;
	zend_long options = 0;
	xmlreader_object *intern = NULL;
	char *source, *uri = NULL, *encoding = NULL;
	int resolved_path_len, ret = 0;
	char *directory=NULL, resolved_path[MAXPATHLEN];
	xmlParserInputBufferPtr inputbfr;
	xmlTextReaderPtr reader;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!l", &source, &source_len, &encoding, &encoding_len, &options) == FAILURE) {
		return;
	}

	id = getThis();
	if (id != NULL && ! instanceof_function(Z_OBJCE_P(id), xmlreader_class_entry)) {
		id = NULL;
	}
	if (id != NULL) {
		intern = Z_XMLREADER_P(id);
		xmlreader_free_resources(intern);
	}

	if (!source_len) {
		php_error_docref(NULL, E_WARNING, "Empty string supplied as input");
		RETURN_FALSE;
	}

	inputbfr = xmlParserInputBufferCreateMem(source, source_len, XML_CHAR_ENCODING_NONE);

    if (inputbfr != NULL) {
/* Get the URI of the current script so that we can set the base directory in libxml */
#if HAVE_GETCWD
		directory = VCWD_GETCWD(resolved_path, MAXPATHLEN);
#elif HAVE_GETWD
		directory = VCWD_GETWD(resolved_path);
#endif
		if (directory) {
			resolved_path_len = strlen(resolved_path);
			if (resolved_path[resolved_path_len - 1] != DEFAULT_SLASH) {
				resolved_path[resolved_path_len] = DEFAULT_SLASH;
				resolved_path[++resolved_path_len] = '\0';
			}
			uri = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
		}
		reader = xmlNewTextReader(inputbfr, uri);

		if (reader != NULL) {
#if LIBXML_VERSION >= 20628
			ret = xmlTextReaderSetup(reader, NULL, uri, encoding, options);
#endif
			if (ret == 0) {
				if (id == NULL) {
					object_init_ex(return_value, xmlreader_class_entry);
					intern = Z_XMLREADER_P(return_value);
				} else {
					RETVAL_TRUE;
				}
				intern->input = inputbfr;
				intern->ptr = reader;

				if (uri) {
					xmlFree(uri);
				}

				return;
			}
		}
	}

	if (uri) {
		xmlFree(uri);
	}

	if (inputbfr) {
		xmlFreeParserInputBuffer(inputbfr);
	}
	php_error_docref(NULL, E_WARNING, "Unable to load source data");
	RETURN_FALSE;
}
Ejemplo n.º 4
0
static int php_do_open_temporary_file(const char *path, const char *pfx, zend_string **opened_path_p)
{
    char *trailing_slash;
#ifdef PHP_WIN32
    char *opened_path = NULL;
    size_t opened_path_len;
    wchar_t *cwdw, *pfxw, pathw[MAXPATHLEN];
#else
    char opened_path[MAXPATHLEN];
#endif
    char cwd[MAXPATHLEN];
    cwd_state new_state;
    int fd = -1;
#ifndef HAVE_MKSTEMP
    int open_flags = O_CREAT | O_TRUNC | O_RDWR
#ifdef PHP_WIN32
                     | _O_BINARY
#endif
                     ;
#endif

    if (!path || !path[0]) {
        return -1;
    }

#ifdef PHP_WIN32
    if (!php_win32_check_trailing_space(pfx, (const int)strlen(pfx))) {
        SetLastError(ERROR_INVALID_NAME);
        return -1;
    }
#endif

    if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
        cwd[0] = '\0';
    }

    new_state.cwd = estrdup(cwd);
    new_state.cwd_length = (int)strlen(cwd);

    if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH)) {
        efree(new_state.cwd);
        return -1;
    }

    if (IS_SLASH(new_state.cwd[new_state.cwd_length - 1])) {
        trailing_slash = "";
    } else {
        trailing_slash = "/";
    }

#ifndef PHP_WIN32
    if (snprintf(opened_path, MAXPATHLEN, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, pfx) >= MAXPATHLEN) {
        efree(new_state.cwd);
        return -1;
    }
#endif

#ifdef PHP_WIN32
    cwdw = php_win32_ioutil_any_to_w(new_state.cwd);
    pfxw = php_win32_ioutil_any_to_w(pfx);
    if (!cwdw || !pfxw) {
        free(cwdw);
        free(pfxw);
        efree(new_state.cwd);
        return -1;
    }

    if (GetTempFileNameW(cwdw, pfxw, 0, pathw)) {
        opened_path = php_win32_ioutil_conv_w_to_any(pathw, PHP_WIN32_CP_IGNORE_LEN, &opened_path_len);
        if (!opened_path || opened_path_len >= MAXPATHLEN) {
            free(cwdw);
            free(pfxw);
            efree(new_state.cwd);
            return -1;
        }
        assert(strlen(opened_path) == opened_path_len);

        /* Some versions of windows set the temp file to be read-only,
         * which means that opening it will fail... */
        if (VCWD_CHMOD(opened_path, 0600)) {
            free(cwdw);
            free(pfxw);
            efree(new_state.cwd);
            free(opened_path);
            return -1;
        }
        fd = VCWD_OPEN_MODE(opened_path, open_flags, 0600);
    }

    free(cwdw);
    free(pfxw);
#elif defined(HAVE_MKSTEMP)
    fd = mkstemp(opened_path);
#else
    if (mktemp(opened_path)) {
        fd = VCWD_OPEN(opened_path, open_flags);
    }
#endif

#ifdef PHP_WIN32
    if (fd != -1 && opened_path_p) {
        *opened_path_p = zend_string_init(opened_path, opened_path_len, 0);
    }
    free(opened_path);
#else
    if (fd != -1 && opened_path_p) {
        *opened_path_p = zend_string_init(opened_path, strlen(opened_path), 0);
    }
#endif
    efree(new_state.cwd);
    return fd;
}
Ejemplo n.º 5
0
PHPAPI int php_checkuid_ex(const char *filename, const char *fopen_mode, int mode, int flags)
{
	struct stat sb;
	int ret, nofile=0;
	long uid=0L, gid=0L, duid=0L, dgid=0L;
	char path[MAXPATHLEN];
	char *s, filenamecopy[MAXPATHLEN];
	TSRMLS_FETCH();

	path[0] = '\0';

	if (!filename) {
		return 0; /* path must be provided */
	}

	if (strlcpy(filenamecopy, filename, MAXPATHLEN)>=MAXPATHLEN) {
		return 0;
	}
	filename=(char *)&filenamecopy;

	if (fopen_mode) {
		if (fopen_mode[0] == 'r') {
			mode = CHECKUID_DISALLOW_FILE_NOT_EXISTS;
		} else {
			mode = CHECKUID_CHECK_FILE_AND_DIR;
		}
	}
		
	/* First we see if the file is owned by the same user...
	 * If that fails, passthrough and check directory...
	 */
	if (mode != CHECKUID_ALLOW_ONLY_DIR) {
#if HAVE_BROKEN_GETCWD
		char ftest[MAXPATHLEN];

		strcpy(ftest, filename);
		if (VCWD_GETCWD(ftest, sizeof(ftest)) == NULL) {
			strcpy(path, filename);
		} else
#endif
		expand_filepath(filename, path TSRMLS_CC);

		ret = VCWD_STAT(path, &sb);
		if (ret < 0) {
			if (mode == CHECKUID_DISALLOW_FILE_NOT_EXISTS) {
				if ((flags & CHECKUID_NO_ERRORS) == 0) {
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
				}
				return 0;
			} else if (mode == CHECKUID_ALLOW_FILE_NOT_EXISTS) {
				if ((flags & CHECKUID_NO_ERRORS) == 0) {
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
				}
				return 1;
			} 
			nofile = 1;
		} else {
			uid = sb.st_uid;
			gid = sb.st_gid;
			if (uid == php_getuid()) {
				return 1;
 			} else if (PG(safe_mode_gid) && gid == php_getgid()) {
 				return 1;
			}
		}

		/* Trim off filename */
		if ((s = strrchr(path, DEFAULT_SLASH))) {
			if (*(s + 1) == '\0' && s != path) { /* make sure that the / is not the last character */
				*s = '\0';
				s = strrchr(path, DEFAULT_SLASH);
			}
			if (s) {
				if (s == path) {
					path[1] = '\0';
				} else {
					*s = '\0';
				}
			}
		}
	} else { /* CHECKUID_ALLOW_ONLY_DIR */
		s = strrchr(filename, DEFAULT_SLASH);

		if (s == filename) {
			/* root dir */
			path[0] = DEFAULT_SLASH;
			path[1] = '\0';
		} else if (s && *(s + 1) != '\0') { /* make sure that the / is not the last character */
			*s = '\0';
			VCWD_REALPATH(filename, path);
			*s = DEFAULT_SLASH;
		} else {
			/* Under Solaris, getcwd() can fail if there are no
			 * read permissions on a component of the path, even
			 * though it has the required x permissions */
			path[0] = '.';
			path[1] = '\0';
			VCWD_GETCWD(path, sizeof(path));
 		}
	} /* end CHECKUID_ALLOW_ONLY_DIR */
	
	if (mode != CHECKUID_ALLOW_ONLY_FILE) {
		/* check directory */
		ret = VCWD_STAT(path, &sb);
		if (ret < 0) {
			if ((flags & CHECKUID_NO_ERRORS) == 0) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to access %s", filename);
			}
			return 0;
		}
		duid = sb.st_uid;
		dgid = sb.st_gid;
		if (duid == php_getuid()) {
			return 1;
 		} else if (PG(safe_mode_gid) && dgid == php_getgid()) {
 			return 1;
		} else {
			if (SG(rfc1867_uploaded_files)) {
				if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, strlen(filename)+1)) {
					return 1;
				}
			}
		}
	}

	if (mode == CHECKUID_ALLOW_ONLY_DIR) {
		uid = duid;
		gid = dgid;
		if (s) {
			*s = 0;
		}
	}
	
	if (nofile) {
		uid = duid;
		gid = dgid;
		filename = path;
	}

	if ((flags & CHECKUID_NO_ERRORS) == 0) {
		if (PG(safe_mode_gid)) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect.  The script whose uid/gid is %ld/%ld is not allowed to access %s owned by uid/gid %ld/%ld", php_getuid(), php_getgid(), filename, uid, gid);
		} else {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "SAFE MODE Restriction in effect.  The script whose uid is %ld is not allowed to access %s owned by uid %ld", php_getuid(), filename, uid);
		}			
	}

	return 0;
}
Ejemplo n.º 6
0
static void _php_do_opendir(INTERNAL_FUNCTION_PARAMETERS, int createobject)
{
	pval **arg;
	php_dir *dirp;
	DIRLS_FETCH();
	
	if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
		WRONG_PARAM_COUNT;
	}
	convert_to_string_ex(arg);

	if (php_check_open_basedir((*arg)->value.str.val)) {
		RETURN_FALSE;
	}
	
	dirp = emalloc(sizeof(php_dir));

	dirp->dir = VCWD_OPENDIR((*arg)->value.str.val);

#ifdef PHP_WIN32
	if (!dirp->dir || dirp->dir->finished) {
		if (dirp->dir) {
			closedir(dirp->dir);
		}
#else
	if (!dirp->dir) {
#endif
		efree(dirp);
		php_error(E_WARNING, "OpenDir: %s (errno %d)", strerror(errno), errno);
		RETURN_FALSE;
	}

	dirp->id = zend_list_insert(dirp,le_dirp);

	php_set_default_dir(dirp->id DIRLS_CC);

	if (createobject) {
		object_init_ex(return_value, dir_class_entry_ptr);
		add_property_stringl(return_value, "path", (*arg)->value.str.val, (*arg)->value.str.len, 1);
		add_property_resource(return_value, "handle", dirp->id);
		zend_list_addref(dirp->id);
	} else {
		RETURN_RESOURCE(dirp->id);
	}
}

/* }}} */
/* {{{ proto int opendir(string path)
   Open a directory and return a dir_handle */

PHP_FUNCTION(opendir)
{
	_php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
}

/* }}} */
/* {{{ proto class dir(string directory)
   Directory class with properties, handle and class and methods read, rewind and close */

PHP_FUNCTION(getdir)
{
	_php_do_opendir(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
}

/* }}} */
/* {{{ proto void closedir([int dir_handle])
   Close directory connection identified by the dir_handle */

PHP_FUNCTION(closedir)
{
	pval **id, **tmp, *myself;
	php_dir *dirp;
	DIRLS_FETCH();

	FETCH_DIRP();

	zend_list_delete(dirp->id);

	if (dirp->id == DIRG(default_dir)) {
		php_set_default_dir(-1 DIRLS_CC);
	}
}

/* }}} */

#if defined(HAVE_CHROOT) && !defined(ZTS)
/* {{{ proto int chroot(string directory)
   Change root directory */

PHP_FUNCTION(chroot)
{
	pval **arg;
	int ret;
	
	if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
		WRONG_PARAM_COUNT;
	}
	convert_to_string_ex(arg);

	ret = chroot((*arg)->value.str.val);
	
	if (ret != 0) {
		php_error(E_WARNING, "chroot: %s (errno %d)", strerror(errno), errno);
		RETURN_FALSE;
	}

	ret = chdir("/");
	
	if (ret != 0) {
		php_error(E_WARNING, "chdir: %s (errno %d)", strerror(errno), errno);
		RETURN_FALSE;
	}

	RETURN_TRUE;
}

/* }}} */
#endif

/* {{{ proto int chdir(string directory)
   Change the current directory */

PHP_FUNCTION(chdir)
{
	pval **arg;
	int ret;
	PLS_FETCH();
	
	if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
		WRONG_PARAM_COUNT;
	}
	convert_to_string_ex(arg);

	if (PG(safe_mode) && !php_checkuid((*arg)->value.str.val, NULL, CHECKUID_ALLOW_ONLY_DIR)) {
		RETURN_FALSE;
	}
	ret = VCWD_CHDIR((*arg)->value.str.val);
	
	if (ret != 0) {
		php_error(E_WARNING, "ChDir: %s (errno %d)", strerror(errno), errno);
		RETURN_FALSE;
	}

	RETURN_TRUE;
}

/* }}} */
/* {{{ proto string getcwd(void)
   Gets the current directory */

PHP_FUNCTION(getcwd)
{
	char path[MAXPATHLEN];
	char *ret=NULL;
	
	if (ZEND_NUM_ARGS() != 0) {
		WRONG_PARAM_COUNT;
	}

#if HAVE_GETCWD
	ret = VCWD_GETCWD(path, MAXPATHLEN);
#elif HAVE_GETWD
	ret = VCWD_GETWD(path);
/*
 * #warning is not ANSI C
 * #else
 * #warning no proper getcwd support for your site
 */
#endif

	if (ret) {
		RETURN_STRING(path,1);
	} else {
		RETURN_FALSE;
	}
}

/* }}} */
/* {{{ proto void rewinddir([int dir_handle])
   Rewind dir_handle back to the start */

PHP_FUNCTION(rewinddir)
{
	pval **id, **tmp, *myself;
	php_dir *dirp;
	DIRLS_FETCH();
	
	FETCH_DIRP();

	rewinddir(dirp->dir);
}
/* }}} */
/* {{{ proto string readdir([int dir_handle])
   Read directory entry from dir_handle */

PHP_NAMED_FUNCTION(php_if_readdir)
{
	pval **id, **tmp, *myself;
	php_dir *dirp;
	char entry[sizeof(struct dirent)+MAXPATHLEN];
	struct dirent *result = (struct dirent *)&entry; /* patch for libc5 readdir problems */
	DIRLS_FETCH();

	FETCH_DIRP();

	if (php_readdir_r(dirp->dir, (struct dirent *) entry, &result) == 0 && result) {
		RETURN_STRINGL(result->d_name, strlen(result->d_name), 1);
	}
	RETURN_FALSE;
}