]> git.mjollnir.org Git - s9y.git/commitdiff
1.1-alpha1: Commit directory image permission system.
authorgarvinhicking <garvinhicking>
Wed, 8 Feb 2006 16:48:28 +0000 (16:48 +0000)
committergarvinhicking <garvinhicking>
Wed, 8 Feb 2006 16:48:28 +0000 (16:48 +0000)
Version bump.

bundled-libs/HTTP/Request.php
docs/NEWS
include/admin/images.inc.php
include/functions_config.inc.php
include/functions_images.inc.php
serendipity_admin_image_selector.php
serendipity_config.inc.php

index 5b7ed0fef26fa74af8eb3c43f8a7435c248cad11..7db3634d65c642e0fd9e01e9ac22cba7dab0c21c 100644 (file)
@@ -32,7 +32,7 @@
 // | Author: Richard Heyes <richard@phpguru.org>                           |
 // +-----------------------------------------------------------------------+
 //
-// $Id: Request.php,v 1.41 2004/12/10 14:42:57 avb Exp $
+// $Id: Request.php,v 1.43 2005/11/06 18:29:14 avb Exp $
 //
 // HTTP_Request Class
 //
@@ -128,10 +128,22 @@ class HTTP_Request {
 
     /**
     * Post data
-    * @var mixed
+    * @var array
     */
     var $_postData;
 
+   /**
+    * Request body  
+    * @var string
+    */
+    var $_body;
+
+   /**
+    * A list of methods that MUST NOT have a request body, per RFC 2616
+    * @var array
+    */
+    var $_bodyDisallowed = array('TRACE');
+
    /**
     * Files to post 
     * @var array
@@ -229,7 +241,8 @@ class HTTP_Request {
         $this->_method         =  HTTP_REQUEST_METHOD_GET;
         $this->_http           =  HTTP_REQUEST_HTTP_VER_1_1;
         $this->_requestHeaders = array();
-        $this->_postData       = null;
+        $this->_postData       = array();
+        $this->_body           = null;
 
         $this->_user = null;
         $this->_pass = null;
@@ -262,7 +275,7 @@ class HTTP_Request {
 
         // Basic authentication
         if (!empty($this->_user)) {
-            $this->_requestHeaders['Authorization'] = 'Basic ' . base64_encode($this->_user . ':' . $this->_pass);
+            $this->addHeader('Authorization', 'Basic ' . base64_encode($this->_user . ':' . $this->_pass));
         }
 
         // Use gzip encoding if possible
@@ -398,7 +411,7 @@ class HTTP_Request {
     */
     function addHeader($name, $value)
     {
-        $this->_requestHeaders[$name] = $value;
+        $this->_requestHeaders[strtolower($name)] = $value;
     }
 
     /**
@@ -409,8 +422,8 @@ class HTTP_Request {
     */
     function removeHeader($name)
     {
-        if (isset($this->_requestHeaders[$name])) {
-            unset($this->_requestHeaders[$name]);
+        if (isset($this->_requestHeaders[strtolower($name)])) {
+            unset($this->_requestHeaders[strtolower($name)]);
         }
     }
 
@@ -509,15 +522,27 @@ class HTTP_Request {
     }
 
     /**
-    * Adds raw postdata
+    * Adds raw postdata (DEPRECATED)
     *
     * @param string     The data
     * @param bool       Whether data is preencoded or not, default = already encoded
     * @access public
+    * @deprecated       deprecated since 1.3.0, method addBody() should be used instead
     */
     function addRawPostData($postdata, $preencoded = true)
     {
-        $this->_postData = $preencoded ? $postdata : urlencode($postdata);
+        $this->_body = $preencoded ? $postdata : urlencode($postdata);
+    }
+
+   /**
+    * Sets the request body (for POST, PUT and similar requests)
+    *
+    * @param    string  Request body
+    * @access   public
+    */
+    function setBody($body)
+    {
+        $this->_body = $body;
     }
 
     /**
@@ -542,7 +567,7 @@ class HTTP_Request {
     */
     function addCookie($name, $value)
     {
-        $cookies = isset($this->_requestHeaders['Cookie']) ? $this->_requestHeaders['Cookie']. '; ' : '';
+        $cookies = isset($this->_requestHeaders['cookie']) ? $this->_requestHeaders['cookie']. '; ' : '';
         $this->addHeader('Cookie', $cookies . $name . '=' . $value);
     }
     
@@ -585,28 +610,35 @@ class HTTP_Request {
             $host = 'ssl://' . $host;
         }
 
+        // magic quotes may fuck up file uploads and chunked response processing
+        $magicQuotes = ini_get('magic_quotes_runtime');
+        ini_set('magic_quotes_runtime', false);
+
         // If this is a second request, we may get away without
         // re-connecting if they're on the same server
-        if (PEAR::isError($err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions)) ||
-            PEAR::isError($err = $this->_sock->write($this->_buildRequest()))) {
+        $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions);
+        PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest());
 
-            return $err;
-        }
-        if (!empty($this->_readTimeout)) {
-            $this->_sock->setTimeout($this->_readTimeout[0], $this->_readTimeout[1]);
+        if (!PEAR::isError($err)) {
+            if (!empty($this->_readTimeout)) {
+                $this->_sock->setTimeout($this->_readTimeout[0], $this->_readTimeout[1]);
+            }
+
+            $this->_notify('sentRequest');
+
+            // Read the response
+            $this->_response = &new HTTP_Response($this->_sock, $this->_listeners);
+            $err = $this->_response->process($this->_saveBody && $saveBody);
         }
 
-        $this->_notify('sentRequest');
+        ini_set('magic_quotes_runtime', $magicQuotes);
 
-        // Read the response
-        $this->_response = &new HTTP_Response($this->_sock, $this->_listeners);
-        if (PEAR::isError($err = $this->_response->process($this->_saveBody && $saveBody)) ) {
+        if (PEAR::isError($err)) {
             return $err;
         }
 
+
         // Check for redirection
-        // Bugfix (PEAR) bug #18, 6 oct 2003 by Dave Mertens (headers are also stored lowercase, so we're gonna use them here)
-        // some non RFC2616 compliant servers (scripts) are returning lowercase headers ('location: xxx')
         if (    $this->_allowRedirects
             AND $this->_redirects <= $this->_maxRedirects
             AND $this->getResponseCode() > 300
@@ -681,6 +713,7 @@ class HTTP_Request {
         if (!isset($headername)) {
             return isset($this->_response->_headers)? $this->_response->_headers: array();
         } else {
+            $headername = strtolower($headername);
             return isset($this->_response->_headers[$headername]) ? $this->_response->_headers[$headername] : false;
         }
     }
@@ -727,13 +760,16 @@ class HTTP_Request {
 
         $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n";
 
-        if (HTTP_REQUEST_METHOD_POST != $this->_method && HTTP_REQUEST_METHOD_PUT != $this->_method) {
+        if (in_array($this->_method, $this->_bodyDisallowed) ||
+            (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_body)) ||
+            (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_postData) && empty($this->_postFiles))) {
+
             $this->removeHeader('Content-Type');
         } else {
-            if (empty($this->_requestHeaders['Content-Type'])) {
+            if (empty($this->_requestHeaders['content-type'])) {
                 // Add default content-type
                 $this->addHeader('Content-Type', 'application/x-www-form-urlencoded');
-            } elseif ('multipart/form-data' == $this->_requestHeaders['Content-Type']) {
+            } elseif ('multipart/form-data' == $this->_requestHeaders['content-type']) {
                 $boundary = 'HTTP_Request_' . md5(uniqid('request') . microtime());
                 $this->addHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary);
             }
@@ -742,17 +778,21 @@ class HTTP_Request {
         // Request Headers
         if (!empty($this->_requestHeaders)) {
             foreach ($this->_requestHeaders as $name => $value) {
-                $request .= $name . ': ' . $value . "\r\n";
+                $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
+                $request      .= $canonicalName . ': ' . $value . "\r\n";
             }
         }
 
         // No post data or wrong method, so simply add a final CRLF
-        if ((HTTP_REQUEST_METHOD_POST != $this->_method && HTTP_REQUEST_METHOD_PUT != $this->_method) ||
-            (empty($this->_postData) && empty($this->_postFiles))) {
+        if (in_array($this->_method, $this->_bodyDisallowed) || 
+            (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_body))) {
 
             $request .= "\r\n";
+
         // Post data if it's an array
-        } elseif ((!empty($this->_postData) && is_array($this->_postData)) || !empty($this->_postFiles)) {
+        } elseif (HTTP_REQUEST_METHOD_POST == $this->_method && 
+                  (!empty($this->_postData) || !empty($this->_postFiles))) {
+
             // "normal" POST request
             if (!isset($boundary)) {
                 $postdata = implode('&', array_map(
@@ -791,15 +831,16 @@ class HTTP_Request {
                         $postdata .= "\r\n\r\n" . $data . "\r\n";
                     }
                 }
-                $postdata .= '--' . $boundary . "\r\n";
+                $postdata .= '--' . $boundary . "--\r\n";
             }
             $request .= 'Content-Length: ' . strlen($postdata) . "\r\n\r\n";
             $request .= $postdata;
 
-        // Post data if it's raw
-        } elseif(!empty($this->_postData)) {
-            $request .= 'Content-Length: ' . strlen($this->_postData) . "\r\n\r\n";
-            $request .= $this->_postData;
+        // Explicitly set request body
+        } elseif (!empty($this->_body)) {
+
+            $request .= 'Content-Length: ' . strlen($this->_body) . "\r\n\r\n";
+            $request .= $this->_body;
         }
         
         return $request;
@@ -995,18 +1036,22 @@ class HTTP_Response
         $chunked = isset($this->_headers['transfer-encoding']) && ('chunked' == $this->_headers['transfer-encoding']);
         $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']);
         $hasBody = false;
-        while (!$this->_sock->eof()) {
-            if ($chunked) {
-                $data = $this->_readChunked();
-            } else {
-                $data = $this->_sock->read(4096);
-            }
-            if ('' != $data) {
-                $hasBody = true;
-                if ($saveBody || $gzipped) {
-                    $this->_body .= $data;
+        if (!isset($this->_headers['content-length']) || 0 != $this->_headers['content-length']) {
+            while (!$this->_sock->eof()) {
+                if ($chunked) {
+                    $data = $this->_readChunked();
+                } else {
+                    $data = $this->_sock->read(4096);
+                }
+                if ('' == $data) {
+                    break;
+                } else {
+                    $hasBody = true;
+                    if ($saveBody || $gzipped) {
+                        $this->_body .= $data;
+                    }
+                    $this->_notify($gzipped? 'gzTick': 'tick', $data);
                 }
-                $this->_notify($gzipped? 'gzTick': 'tick', $data);
             }
         }
         if ($hasBody) {
@@ -1031,12 +1076,15 @@ class HTTP_Response
     function _processHeader($header)
     {
         list($headername, $headervalue) = explode(':', $header, 2);
-        $headername_i = strtolower($headername);
-        $headervalue  = ltrim($headervalue);
+        $headername  = strtolower($headername);
+        $headervalue = ltrim($headervalue);
         
-        if ('set-cookie' != $headername_i) {
-            $this->_headers[$headername]   = $headervalue;
-            $this->_headers[$headername_i] = $headervalue;
+        if ('set-cookie' != $headername) {
+            if (isset($this->_headers[$headername])) {
+                $this->_headers[$headername] .= ',' . $headervalue;
+            } else {
+                $this->_headers[$headername]  = $headervalue;
+            }
         } else {
             $this->_parseCookie($headervalue);
         }
@@ -1109,10 +1157,10 @@ class HTTP_Response
                 $this->_chunkLength = hexdec($matches[1]); 
                 // Chunk with zero length indicates the end
                 if (0 == $this->_chunkLength) {
-                    $this->_sock->readAll(); // make this an eof()
+                    $this->_sock->readLine(); // make this an eof()
                     return '';
                 }
-            } elseif ($this->_sock->eof()) {
+            } else {
                 return '';
             }
         }
index 332a7d73bbd16d2dbdad19c2de2d493bd1730916..6c6a7edcb5461ec85bc08d47ec31f1652337c3a6 100644 (file)
--- a/docs/NEWS
+++ b/docs/NEWS
@@ -1,5 +1,10 @@
 # $Id$
 
+Version 1.1-alpha1()
+------------------------------------------------------------------------
+
+   * Added first patches for image directory permissions. (garvinhicking)
+
 Version 1.0-beta2 ()
 ------------------------------------------------------------------------
 
index 4d57de9310b03e895d7f450d209c2ec4e8bf073a..c94d593839eaf2359c3573186724f247383ad0c6 100644 (file)
@@ -44,7 +44,7 @@ switch ($serendipity['GET']['adminAction']) {
     case 'delete':
         $file     = serendipity_fetchImageFromDatabase($serendipity['GET']['fid']);
 
-        if (!serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
+        if (!is_array($file) || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
             return;
         }
 
@@ -52,7 +52,7 @@ switch ($serendipity['GET']['adminAction']) {
             $serendipity['adminFile'] = 'serendipity_admin.php';
         }
         $abortLoc = $serendipity['serendipityHTTPPath'] . $serendipity['adminFile'] . '?serendipity[adminModule]=images';
-        $newLoc   = $abortLoc . '&serendipity[adminAction]=DoDelete&serendipity[fid]=' . $serendipity['GET']['fid'] . '&' . serendipity_setFormToken('url');
+        $newLoc   = $abortLoc . '&serendipity[adminAction]=DoDelete&serendipity[fid]=' . (int)$serendipity['GET']['fid'] . '&' . serendipity_setFormToken('url');
 
         printf(ABOUT_TO_DELETE_FILE, $file['name'] .'.'. $file['extension']);
 ?>
@@ -70,12 +70,12 @@ switch ($serendipity['GET']['adminAction']) {
         $file = serendipity_fetchImageFromDatabase($serendipity['GET']['fid']);
         $serendipity['GET']['newname'] = serendipity_uploadSecure($serendipity['GET']['newname'], true);
 
-        if (!serendipity_checkFormToken() || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
+        if (!is_array($file) || !serendipity_checkFormToken() || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
             return;
         }
 
         if (serendipity_isActiveFile(basename($serendipity['GET']['newname']))) {
-            printf(ERROR_FILE_FORBIDDEN, $serendipity['GET']['newname']);
+            printf(ERROR_FILE_FORBIDDEN, htmlspecialchars($serendipity['GET']['newname']));
             return;
         }
 
@@ -302,6 +302,34 @@ switch ($serendipity['GET']['adminAction']) {
 
         break;
 
+    case 'directoryEdit':
+        if (!serendipity_checkPermission('adminImagesDirectories')) {
+            return;
+        }
+
+?>
+
+    <strong><?php echo MANAGE_DIRECTORIES ?></strong><br />
+    <br />
+    <form method="POST" action="?serendipity[adminModule]=images&serendipity[adminAction]=directoryDoEdit&amp;serendipity[dir]=<?php echo htmlspecialchars($serendipity['GET']['dir']) ?>">
+    <?php echo serendipity_setFormToken(); ?> 
+    <input type="hidden" name="serendipity[oldDir]" value="<?php echo serendipity_uploadSecure($serendipity['GET']['dir']); ?>" />
+    <table cellpadding="5">
+        <tr>
+            <td width="100"><strong><?php echo NAME ?></strong></td>
+            <input type="hidden" name="serendipity[newDir]" value="<?php echo serendipity_uploadSecure($serendipity['GET']['dir']); ?>" />
+        </tr>
+    </table>
+    <br />
+    <br />
+    <div align="center">
+        <input name="SAVE" value="<?php echo SAVE ?>" class="serendipityPrettyButton" type="submit" />
+    </div>
+    </form>
+
+<?php
+        break;
+
     case 'directoryDelete':
         if (!serendipity_checkPermission('adminImagesDirectories')) {
             return;
@@ -312,12 +340,12 @@ switch ($serendipity['GET']['adminAction']) {
     <?php echo DELETE_DIRECTORY_DESC ?>
     <br />
     <br />
-    <form method="POST" action="?serendipity[adminModule]=images&serendipity[adminAction]=directoryDoDelete&amp;serendipity[dir]=<?php echo $serendipity['GET']['dir'] ?>">
+    <form method="POST" action="?serendipity[adminModule]=images&serendipity[adminAction]=directoryDoDelete&amp;serendipity[dir]=<?php echo htmlspecialchars($serendipity['GET']['dir']) ?>">
     <?php echo serendipity_setFormToken(); ?> 
     <table cellpadding="5">
         <tr>
             <td width="100"><strong><?php echo NAME ?></strong></td>
-            <td><?php echo basename($serendipity['GET']['dir']) ?></td>
+            <td><?php echo basename(htmlspecialchars($serendipity['GET']['dir'])) ?></td>
         </tr>
         <tr>
             <td colspan="2"><input type="checkbox" name="serendipity[nuke]" value="true" style="margin: 0"> <?php echo FORCE_DELETE ?></td>
@@ -326,8 +354,8 @@ switch ($serendipity['GET']['adminAction']) {
     <br />
     <br />
     <div align="center">
-        <?php echo sprintf(CONFIRM_DELETE_DIRECTORY, $serendipity['GET']['dir']) ?><br />
-        <input name="SAVE" value="<?php echo DELETE_DIRECTORY ?>" class="serendipityPrettyButton" type="submit">
+        <?php echo sprintf(CONFIRM_DELETE_DIRECTORY, htmlspecialchars($serendipity['GET']['dir'])) ?><br />
+        <input name="SAVE" value="<?php echo DELETE_DIRECTORY ?>" class="serendipityPrettyButton" type="submit" />
     </div>
     </form>
 
@@ -357,6 +385,16 @@ switch ($serendipity['GET']['adminAction']) {
         if (!serendipity_checkPermission('adminImagesDirectories')) {
             return;
         }
+
+        $folders = serendipity_traversePath(
+            $serendipity['serendipityPath'] . $serendipity['uploadPath'],
+            '',
+            true,
+            NULL,
+            1,
+            NULL,
+            'write'
+        );
 ?>
     <strong><?php echo CREATE_DIRECTORY ?></strong><br />
     <?php echo CREATE_DIRECTORY_DESC ?>
@@ -373,7 +411,7 @@ switch ($serendipity['GET']['adminAction']) {
             <td><?php echo PARENT_DIRECTORY ?></td>
             <td><select name="serendipity[parent]">
                     <option value=""><?php echo BASE_DIRECTORY ?></option>
-                <?php foreach ( serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']) as $folder ) { ?>
+                <?php foreach ( $folders as $folder ) { ?>
                     <option value="<?php echo $folder['relpath'] ?>"><?php echo str_repeat('&nbsp;', $folder['depth']*2) . ' '. $folder['name'] ?></option>
                 <?php } ?>
                 </select>
@@ -390,17 +428,28 @@ switch ($serendipity['GET']['adminAction']) {
             return;
         }
 
+        $folders = serendipity_traversePath(
+            $serendipity['serendipityPath'] . $serendipity['uploadPath'],
+            '',
+            true,
+            NULL,
+            1,
+            NULL,
+            'write'
+        );
+
 ?>
     <br />
     <?php echo DIRECTORIES_AVAILABLE; ?>
     <br />
     <table border="0" cellspacing="0" cellpadding="4" width="100%">
         <tr>
-            <td colspan="2"><strong><?php echo BASE_DIRECTORY ?></strong></td>
+            <td colspan="3"><strong><?php echo BASE_DIRECTORY ?></strong></td>
         </tr>
-        <?php foreach ( serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']) as $folder ) { ?>
+        <?php foreach ($folders as $folder) { ?>
         <tr>
-            <td width="16"><a href="?serendipity[adminModule]=images&amp;serendipity[adminAction]=directoryDelete&amp;serendipity[dir]=<?php echo urlencode($folder['relpath']) ?>"><img src="<?php echo serendipity_getTemplateFile('admin/img/delete.png') ?>" alt="<?php echo DELETE ?>" border="0"></a></td>
+            <td width="16"><a href="?serendipity[adminModule]=images&amp;serendipity[adminAction]=directoryEdit&amp;serendipity[dir]=<?php echo htmlspecialchars($folder['relpath']) ?>"><img src="<?php echo serendipity_getTemplateFile('admin/img/edit.png') ?>" border="0" alt="<?php echo EDIT ?>" /></a></td>
+            <td width="16"><a href="?serendipity[adminModule]=images&amp;serendipity[adminAction]=directoryDelete&amp;serendipity[dir]=<?php echo htmlspecialchars($folder['relpath']) ?>"><img src="<?php echo serendipity_getTemplateFile('admin/img/delete.png') ?>" alt="<?php echo DELETE ?>" border="0"></a></td>
             <td style="padding-left: <?php echo $folder['depth']*10 ?>"><?php echo $folder['name'] ?></td>
         </tr>
         <?php } ?>
@@ -417,6 +466,15 @@ switch ($serendipity['GET']['adminAction']) {
         }
 
         serendipity_restoreVar($serendipity['COOKIE']['addmedia_directory'], $serendipity['GET']['only_path']);
+        $folders = serendipity_traversePath(
+            $serendipity['serendipityPath'] . $serendipity['uploadPath'],
+            '',
+            true,
+            NULL,
+            1,
+            NULL,
+            'write'
+        );
 ?>
     <?php echo ADD_MEDIA_BLAHBLAH; ?>
 
@@ -650,7 +708,7 @@ switch ($serendipity['GET']['adminAction']) {
                     <td><?php echo STORE_IN_DIRECTORY; ?></td>
                     <td><select id="target_directory_1" name="serendipity[target_directory][1]">
                         <option value=""><?php echo BASE_DIRECTORY; ?></option>
-                        <?php foreach (serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']) as $folder) { ?>
+                        <?php foreach ($folders as $folder) { ?>
                         <option <?php echo ($serendipity['GET']['only_path'] == $folder['relpath']) ? 'selected="selected"' : '' ?> value="<?php echo $folder['relpath'] ?>"><?php echo str_repeat('&nbsp;', $folder['depth']*2) . ' '. $folder['name'] ?></option>
                         <?php } ?>
                         </select>
@@ -685,7 +743,7 @@ switch ($serendipity['GET']['adminAction']) {
 
     case 'rotateCW':
         $file = serendipity_fetchImageFromDatabase($serendipity['GET']['fid']);
-        if (!serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
+        if (!is_array($file) || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
             return;
         }
 
@@ -701,7 +759,7 @@ switch ($serendipity['GET']['adminAction']) {
 
     case 'rotateCCW':
         $file = serendipity_fetchImageFromDatabase($serendipity['GET']['fid']);
-        if (!serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
+        if (!is_array($file) || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
             return;
         }
 
@@ -718,7 +776,7 @@ switch ($serendipity['GET']['adminAction']) {
     case 'scale':
         $file = serendipity_fetchImageFromDatabase($serendipity['GET']['fid']);
 
-        if (!serendipity_checkFormToken() || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
+        if (!is_array($file) || !serendipity_checkFormToken() || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
             return;
         }
 
@@ -726,8 +784,8 @@ switch ($serendipity['GET']['adminAction']) {
           SCALING_IMAGE . '<br />',
 
           $file['path'] . $file['name'] .'.'. $file['extension'],
-          $serendipity['GET']['width'],
-          $serendipity['GET']['height']
+          (int)$serendipity['GET']['width'],
+          (int)$serendipity['GET']['height']
         );
 
         echo serendipity_scaleImg($serendipity['GET']['fid'], $serendipity['GET']['width'], $serendipity['GET']['height']) . '<br />';
@@ -744,7 +802,7 @@ switch ($serendipity['GET']['adminAction']) {
     case 'scaleSelect':
         $file = serendipity_fetchImageFromDatabase($serendipity['GET']['fid']);
 
-        if (!serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
+        if (!is_array($file) || !serendipity_checkPermission('adminImagesDelete') || (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid'])) {
             return;
         }
 
@@ -774,7 +832,7 @@ switch ($serendipity['GET']['adminAction']) {
     </script>
 <?php
 
-        printf(RESIZE_BLAHBLAH, $serendipity['GET']['fname']);
+        printf(RESIZE_BLAHBLAH, htmlspecialchars($serendipity['GET']['fname']));
         printf(ORIGINAL_SIZE, $s[0],$s[1]);
         echo HERE_YOU_CAN_ENTER_BLAHBLAH;
 ?>
index 1005f4d57bffc2a2ca0eb7231a468941d83753c3..ea01de6978c931411a316ab2bdba2977949637a7 100644 (file)
@@ -1351,9 +1351,10 @@ function serendipity_addDefaultGroup($name, $level) {
  * @param   string  The type of an artifact (category|entry)
  * @param   string  The type of access to grant (read|write)
  * @param   array   The ID of the group to grant access to
+ * @param   string  A variable option for an artifact
  * @return  boolean True if ACL was applied, false if not.
  */
-function serendipity_ACLGrant($artifact_id, $artifact_type, $artifact_mode, $groups) {
+function serendipity_ACLGrant($artifact_id, $artifact_type, $artifact_mode, $groups, $artifact_index = '') {
     global $serendipity;
 
     if (empty($groups) || !is_array($groups)) {
@@ -1362,15 +1363,16 @@ function serendipity_ACLGrant($artifact_id, $artifact_type, $artifact_mode, $gro
 
     // Delete all old existing relations.
     serendipity_db_query("DELETE FROM {$serendipity['dbPrefix']}access
-                                WHERE artifact_id   = " . (int)$artifact_id . "
-                                  AND artifact_type = '" . serendipity_db_escape_string($artifact_type) . "'
-                                  AND artifact_mode = '" . serendipity_db_escape_string($artifact_mode) . "'");
+                                WHERE artifact_id    = " . (int)$artifact_id . "
+                                  AND artifact_type  = '" . serendipity_db_escape_string($artifact_type) . "'
+                                  AND artifact_mode  = '" . serendipity_db_escape_string($artifact_mode) . "'
+                                  AND artifact_index = '" . serendipity_db_escape_string($artifact_index) . "'");
 
     $data = array(
         'artifact_id'    => (int)$artifact_id,
         'artifact_type'  => $artifact_type,
         'artifact_mode'  => $artifact_mode,
-        'artifact_index' => ''
+        'artifact_index' => $artifact_index
     );
 
     if (count($data) < 1) {
@@ -1398,15 +1400,17 @@ function serendipity_ACLGrant($artifact_id, $artifact_type, $artifact_mode, $gro
  * @param   int     The ID of the artifact to set the access
  * @param   string  The type of an artifact (category|entry)
  * @param   string  The type of access to check for (read|write)
+ * @param   string  A variable option for an artifact
  * @return  array   Returns an array of all groups that are allowed for this kind of access. You can then check if you are the member of any of the groups returned here.
  */
-function serendipity_ACLGet($artifact_id, $artifact_type, $artifact_mode) {
+function serendipity_ACLGet($artifact_id, $artifact_type, $artifact_mode, $artifact_index) {
     global $serendipity;
 
     $sql = "SELECT groupid, artifact_index FROM {$serendipity['dbPrefix']}access
-                    WHERE artifact_type = '" . serendipity_db_escape_string($artifact_type) . "'
-                      AND artifact_id   = '" . (int)$artifact_id . "'
-                      AND artifact_mode = '" . serendipity_db_escape_string($artifact_mode) . "'";
+                    WHERE artifact_type  = '" . serendipity_db_escape_string($artifact_type) . "'
+                      AND artifact_id    = '" . (int)$artifact_id . "'
+                      AND artifact_mode  = '" . serendipity_db_escape_string($artifact_mode) . "'
+                      AND artifact_index = '" . serendipity_db_escape_string($artifact_index) . "'";
     $rows = serendipity_db_query($sql, false, 'assoc');
 
     if (!is_array($rows)) {
@@ -1491,9 +1495,10 @@ function serendipity_ACLCheck($authorid, $artifact_id, $artifact_type, $artifact
  * @access private
  * @param   array       Associative array that holds the SQL part array to be used in other functions like serendipity_fetchEntries()
  * @param   boolean     Some queries do not need to joins categories. When ACLs need to be applied, this column is required, so if $append_category is set to true it will perform this missing JOIN.
+ * @param   string      The ACL type ('category', 'directory')
  * @return  true        True if ACLs were applied, false if not.
  */
-function serendipity_ACL_SQL(&$cond, $append_category = false) {
+function serendipity_ACL_SQL(&$cond, $append_category = false, $type = 'category') {
     global $serendipity;
 
     // A global configuration item controls whether the blog should apply ACLs or not!
@@ -1518,13 +1523,26 @@ function serendipity_ACL_SQL(&$cond, $append_category = false) {
             $cond['joins'] .= " LEFT JOIN {$serendipity['dbPrefix']}category c
                                        ON ec.categoryid = c.categoryid";
         }
+        
+        switch($type) {
+            case 'directory':
+                $sql_artifact_column = 'i.path IS NULL OR 
+                                        acl_acc.groupid IS NULL';
+                $sql_artifact = 'AND acl_acc.artifact_index = i.path';
+                break;
+
+            case 'category':
+                $sql_artifact_column = 'c.categoryid IS NULL';
+                $sql_artifact = 'AND acl_acc.artifact_id   = c.categoryid';
+                break;
+        }
 
         $cond['joins'] .= " LEFT JOIN {$serendipity['dbPrefix']}authorgroups AS acl_a
                                    ON acl_a.authorid = " . $read_id . "
                             LEFT JOIN {$serendipity['dbPrefix']}access AS acl_acc
                                    ON (    acl_acc.artifact_mode = 'read'
-                                       AND acl_acc.artifact_type = 'category'
-                                       AND acl_acc.artifact_id   = c.categoryid
+                                       AND acl_acc.artifact_type = '" . $type . "'
+                                       " . $sql_artifact . "
                                       )";
 
         if (empty($cond['and'])) {
@@ -1535,7 +1553,7 @@ function serendipity_ACL_SQL(&$cond, $append_category = false) {
 
         // When in Admin-Mode, apply readership permissions.
         $cond['and'] .= "    (
-                                 c.categoryid IS NULL
+                                 " . $sql_artifact_column . "
                                  OR ( acl_acc.groupid = " . $read_id_sql . ")
                                  OR ( acl_acc.artifact_id IS NULL
                                       " . (isset($serendipity['GET']['adminModule']) &&
index 953420a39ed316bcef43cd3d34979f35dab215dd..6861a4ecd958020474ce2fadadc4647df13fee32 100644 (file)
@@ -71,13 +71,30 @@ function serendipity_fetchImagesFromDatabase($start=0, $limit=0, &$total, $order
         $permsql = " WHERE $perm";
     }
 
-    $query = "SELECT i.*, a.realname AS authorname FROM {$serendipity['dbPrefix']}images AS i LEFT OUTER JOIN {$serendipity['dbPrefix']}authors AS a ON i.authorid = a.authorid $directorysql ORDER BY $order $ordermode $limitsql";
+    $cond = array(
+        'and' => $directorysql
+    );
+    serendipity_ACL_SQL($cond, false, 'directory');
+
+    $basequery = "FROM {$serendipity['dbPrefix']}images AS i 
+       LEFT OUTER JOIN {$serendipity['dbPrefix']}authors AS a 
+                    ON i.authorid = a.authorid 
+                       {$cond['joins']}
+                       
+                       {$cond['and']}";
+    
+    $query = "SELECT i.*, 
+                     a.realname AS authorname 
+                     $basequery 
+            ORDER BY $order $ordermode $limitsql";
+
     $rs = serendipity_db_query($query, false, 'assoc');
     if (!is_array($rs)) {
         return array();
     }
 
-    $total_query = "SELECT count(i.id) FROM {$serendipity['dbPrefix']}images AS i LEFT OUTER JOIN {$serendipity['dbPrefix']}authors AS a on i.authorid = a.authorid $permsql";
+    $total_query = "SELECT count(i.id) 
+                           $basequery";
     $total_rs = serendipity_db_query($total_query, true, 'num');
     if (is_array($total_rs)) {
         $total = $total_rs[0];
@@ -95,7 +112,16 @@ function serendipity_fetchImagesFromDatabase($start=0, $limit=0, &$total, $order
  */
 function serendipity_fetchImageFromDatabase($id) {
     global $serendipity;
-    $rs = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}images WHERE id = ". (int)$id, true, 'assoc');
+    
+    $cond = array(
+        'and' => "WHERE id = " . (int)$id
+    );
+    serendipity_ACL_SQL($cond, false, 'directory');
+
+    $rs = serendipity_db_query("SELECT i.* 
+                                  FROM {$serendipity['dbPrefix']}images AS i
+                                       {$cond['joins']}
+                                       {$cond['and']}", true, 'assoc');
     return $rs;
 }
 
@@ -138,6 +164,12 @@ function serendipity_deleteImage($id) {
     $dThumb = array();
 
     $file   = serendipity_fetchImageFromDatabase($id);
+
+    if (!is_array($file) || !isset($file['path'])) {
+        printf(FILE_NOT_FOUND . '<br />', $id);
+        return false;
+    }
+
     $dFile  = $file['path'] . $file['name'] . '.' . $file['extension'];
 
     $dThumb = array(array(
@@ -459,6 +491,9 @@ function serendipity_scaleImg($id, $width, $height) {
     global $serendipity;
 
     $file = serendipity_fetchImageFromDatabase($id);
+    if (!is_array($file)) {
+        return false;
+    }
 
     $admin = '';
     if (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid']) {
@@ -496,6 +531,9 @@ function serendipity_rotateImg($id, $degrees) {
     global $serendipity;
 
     $file = serendipity_fetchImageFromDatabase($id);
+    if (!is_array($file)) {
+        return false;
+    }
 
     $admin = '';
     if (!serendipity_checkPermission('adminImagesMaintainOthers') && $file['authorid'] != '0' && $file['authorid'] != $serendipity['authorid']) {
@@ -1107,7 +1145,15 @@ function serendipity_displayImageList($page = 0, $lineBreak = NULL, $manage = fa
     $linkPrevious  = '?' . $extraParems . 'serendipity[page]=' . ($page-1);
     $linkNext      = '?' . $extraParems . 'serendipity[page]=' . ($page+1);
     $sort_order    = serendipity_getImageFields();
-    $paths         = serendipity_traversePath($serendipity['serendipityPath'] . $serendipity['uploadPath']. $limit_path);
+    $paths         = serendipity_traversePath(
+        $serendipity['serendipityPath'] . $serendipity['uploadPath']. $limit_path,
+        '',
+        true,
+        NULL,
+        1,
+        NULL,
+        'read'
+    );
 
     if (is_null($lineBreak)) {
         $lineBreak = floor(750 / ($serendipity['thumbSize'] + 20));
@@ -1407,6 +1453,9 @@ function serendipity_killPath($basedir, $directory = '', $forceDelete = false) {
 /**
  * Recursively walk a directory tree
  *
+ *
+ * @TODO - Check all serendipity_traversePath calls to see where ACL need to be applied
+ *
  * @access public
  * @param   string      The core directory
  * @param   string      The subdirectory
@@ -1414,35 +1463,43 @@ function serendipity_killPath($basedir, $directory = '', $forceDelete = false) {
  * @param   string      A regexp patter to include files
  * @param   int         Level of nesting (recursive use)
  * @param   int         The maximum level of nesting (recursive use)
+ * @param   mixed       Toggle whether to apply serendipity_directoryACL (false / 'read' / 'write')
  * @return  array       Array of files/directories
  */
-function serendipity_traversePath($basedir, $dir='', $onlyDirs=true, $pattern = NULL, $depth = 1, $max_depth = null) {
-
+function serendipity_traversePath($basedir, $dir='', $onlyDirs = true, $pattern = NULL, $depth = 1, $max_depth = null, $apply_ACL = false) {
 
-    $dh = @opendir($basedir . '/' . $dir);
-    if ( !$dh ) {
+    $odir = serendipity_dirSlash('end', $basedir) . serendipity_dirSlash('end', $dir);
+    $dh = @opendir($odir);
+    if (!$dh) {
         return array();
     }
 
     $files = array();
     while (($file = @readdir($dh)) !== false) {
         if ( $file != '.' && $file != '..' ) {
-            if ( $onlyDirs === false || ($onlyDirs === true && is_dir($basedir . '/' . $dir . '/' . $file)) ) {
+            if ( $onlyDirs === false || ($onlyDirs === true && is_dir($odir . $file)) ) {
                 if ( is_null($pattern) || preg_match($pattern, $file) ) {
                     $files[] = array(
                         'name'    => $file,
                         'depth'   => $depth,
-                        'relpath' => ltrim(str_replace('\\', '/', $dir) . basename($file) . '/', '/')
+                        'relpath' => ltrim(str_replace('\\', '/', serendipity_dirSlash('end', $dir)) . basename($file) . '/', '/')
                     );
                 }
             }
-            if ( is_dir($basedir . '/' . $dir . '/' . $file) && ($max_depth === null || $depth < $max_depth)) {
-                $files = array_merge($files, serendipity_traversePath($basedir, $dir . '/' . basename($file) . '/', $onlyDirs, $pattern, ($depth+1), $max_depth));
+
+            if (is_dir($odir . $file) && ($max_depth === null || $depth < $max_depth)) {
+                $next_dir = serendipity_dirSlash('end', $dir) . basename($file);
+                $files = array_merge($files, serendipity_traversePath($basedir, $next_dir, $onlyDirs, $pattern, ($depth+1), $max_depth));
             }
         }
     }
 
     @closedir($dh);
+    
+    if ($depth == 1 && $apply_ACL !== FALSE) {
+        serendipity_directoryACL($files, $apply_ACL);
+    }
+
     return $files;
 }
 
@@ -1569,3 +1626,120 @@ function serendipity_getImageFields() {
 function serendipity_escapeshellarg($string) {
     return escapeshellarg(str_replace('%', '', $string));
 }
+
+/**
+ * Rename a media directory
+ *
+ * @access public
+ * @param   string  Old directory name
+ * @param   string  New directory name
+ */
+function serendipity_renameDir($old, $new) {
+}
+
+/**
+ * Makes sure a directory begins with or ends with a "/"
+ *
+ * @access public
+ * @param   string  Type of where to append/prepend slash ('end', 'start', 'both')
+ * @param   string  Directory name
+ * @return  string  Output argument
+ */
+function serendipity_dirSlash($type, $dir) {
+
+    if ($dir == '') {
+        return $dir;
+    }
+
+    if ($type == 'start' || $type == 'both') {
+        if (substr($dir, 0, 1) != '/') {
+            $dir = '/' . $dir;
+        }
+    }
+
+    if ($type == 'end' || $type == 'both') {
+        if (substr($dir, -1) != '/') {
+            $dir .= '/';
+        }
+    }
+    
+    return $dir;
+}
+
+/**
+ * Cycle a serendipity_traversePath resultset and apply read/write ACLs.
+ *
+ * @access public
+ * @param   array   serendipity_traversePath result array
+ * @param   string  ACL type ('read', 'write')
+ */
+function serendipity_directoryACL(&$paths, $type = 'read') {
+    global $serendipity;
+    static $debug = false;
+    
+    if ($debug) {
+        echo "Applying ACL for mode '$type'.<br />\n";
+    }
+    
+    if (serendipity_userLoggedIn() && (!isset($serendipity['enableACL']) || $serendipity['enableACL'] == true)) {
+        // Check if we are a cool superuser. Bail out if we are.
+        if (serendipity_checkPermission('adminImagesMaintainOthers') && serendipity_checkPermission('adminImagesDirectories')) {
+            if (!$debug) {
+                return true;
+            }
+        }
+        
+        // Get list of all ACLs for directories.
+        $q = "SELECT a.artifact_index AS directory,
+                     a.groupid
+                FROM {$serendipity['dbPrefix']}access AS a
+               WHERE a.artifact_type = 'directory'
+                 AND a.artifact_mode = '" . serendipity_db_escape_string($type) . "'";
+        $allowed = serendipity_db_query($q);
+        if (!is_array($allowed)) {
+            return false;
+        }
+        
+        // Get a list of all the groups for this user. Pipe it into a usable array.
+        $my_groups =& serendipity_getGroups($serendipity['authorid']);
+        $acl_allowed_groups = array();
+        foreach($my_groups AS $my_group) {
+            $acl_allowed_groups[$my_group['id']] = true;
+        }
+        
+        // Iterate every ACL and check if we are allowed to use it.
+        $acl_allowed = array();
+        foreach($allowed AS $row) {
+            $acl_allowed[$row['directory']][$row['groupid']] = true;
+        }
+        
+        // Iterate the input path array and check it against ACL.
+        foreach($paths AS $idx => $info) {
+            if (!isset($acl_allowed[$info['relpath']])) {
+                // ACL for directory not set. Assume we are allowed to access.
+                continue;
+            }
+            
+            $granted = false;
+            foreach($acl_allowed[$info['relpath']] AS $groupid => $set) {
+                if (isset($acl_allowed_groups[$groupid])) {
+                    // We are allowed to access this element
+                    $granted = true;
+                    break;
+                }
+            }
+            
+            if ($granted === false) {
+                // We are not allowed to access this element
+                if ($debug) {
+                    echo "ACL for " . $info['relpath'] . " DENIED.<br />\n";
+                }
+                unset($paths[$idx]);
+            } else {
+                if ($debug) {
+                    echo "ACL for " . $info['relpath'] . " granted.<br />\n";
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
index 386b40dcb44701d78e4b5db57dff0cc58826d96b..9708d74b787b21d816b1de5f5591b2374590a898 100644 (file)
@@ -111,6 +111,10 @@ switch ($serendipity['GET']['step']) {
         }
 
         $file           = serendipity_fetchImageFromDatabase($serendipity['GET']['image']);
+        if (!is_array($file)) {
+            echo PERM_DENIED;
+            break;
+        }
         $file['imgsrc'] = $serendipity['serendipityHTTPPath'] . $serendipity['uploadHTTPPath'] . $file['path'] . $file['name'] . (!empty($file['thumbnail_name']) ? '.' . $file['thumbnail_name'] : '') . '.' . $file['extension'];
         if ($file['hotlink']) {
             $imgName    = $file['path'];
index 90b2dacca88b93dd4897c3ef715ac340b229a766..307f4751bad75fece1f8d70d4fdd9a0d0bbb00b5 100644 (file)
@@ -21,7 +21,7 @@ if (IS_installed === true && !defined('IN_serendipity')) {
 include_once(S9Y_INCLUDE_PATH . 'include/compat.inc.php');
 
 // The version string
-$serendipity['version']         = '1.0-beta2';
+$serendipity['version']         = '1.1-alpha1';
 
 // Name of folder for the default theme
 $serendipity['defaultTemplate'] = 'default';