~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @copyright
 
3
 * ====================================================================
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
 
20
 * ====================================================================
 
21
 * @endcopyright
 
22
 *
 
23
 * @file org_apache_subversion_javahl_util_PropLib.cpp
 
24
 * @brief Implementation of the native methods in the Java class PropLib
 
25
 */
 
26
 
 
27
#include <iostream>
 
28
#include <sstream>
 
29
 
 
30
#include "../include/org_apache_subversion_javahl_util_PropLib.h"
 
31
 
 
32
#include "jniwrapper/jni_stack.hpp"
 
33
#include "jniwrapper/jni_array.hpp"
 
34
#include "jniwrapper/jni_list.hpp"
 
35
#include "jniwrapper/jni_string.hpp"
 
36
#include "jniwrapper/jni_io_stream.hpp"
 
37
#include "ExternalItem.hpp"
 
38
#include "SubversionException.hpp"
 
39
 
 
40
#include "EnumMapper.h"
 
41
#include "Pool.h"
 
42
 
 
43
#include "svn_props.h"
 
44
#include "svn_time.h"
 
45
#include "svn_wc.h"
 
46
 
 
47
#include "private/svn_wc_private.h"
 
48
#include "svn_private_config.h"
 
49
 
 
50
 
 
51
namespace {
 
52
class PropGetter
 
53
{
 
54
public:
 
55
  PropGetter(const char* mime_type, svn_stream_t* contents)
 
56
    : m_mime_type(mime_type),
 
57
      m_contents(contents)
 
58
    {}
 
59
 
 
60
  static svn_error_t* callback(const svn_string_t** mime_type,
 
61
                               svn_stream_t* stream, void* baton,
 
62
                               apr_pool_t* pool)
 
63
    {
 
64
      PropGetter* self = static_cast<PropGetter*>(baton);
 
65
      if (mime_type)
 
66
        {
 
67
          if (self->m_mime_type)
 
68
            *mime_type = svn_string_create(self->m_mime_type, pool);
 
69
          else
 
70
            *mime_type = svn_string_create_empty(pool);
 
71
        }
 
72
 
 
73
      if (stream && self->m_contents)
 
74
        {
 
75
          SVN_ERR(svn_stream_copy3(self->m_contents,
 
76
                                   svn_stream_disown(stream, pool),
 
77
                                   NULL, NULL, pool));
 
78
        }
 
79
 
 
80
      return SVN_NO_ERROR;
 
81
    }
 
82
 
 
83
private:
 
84
  const char* m_mime_type;
 
85
  svn_stream_t* m_contents;
 
86
};
 
87
 
 
88
struct FormatRevision
 
89
{
 
90
  explicit FormatRevision(const svn_opt_revision_t* const& revarg,
 
91
                          const SVN::Pool& poolarg)
 
92
    : rev(revarg), pool(poolarg)
 
93
    {}
 
94
 
 
95
  const svn_opt_revision_t* const& rev;
 
96
  const SVN::Pool& pool;
 
97
};
 
98
 
 
99
std::ostream& operator<<(std::ostream& os, const FormatRevision& pr)
 
100
{
 
101
  switch (pr.rev->kind)
 
102
    {
 
103
    case svn_opt_revision_number:
 
104
      os << pr.rev->value.number;
 
105
      break;
 
106
    case svn_opt_revision_date:
 
107
      os << '{'
 
108
         << svn_time_to_cstring(pr.rev->value.date, pr.pool.getPool())
 
109
         << '}';
 
110
      break;
 
111
    default:
 
112
      throw std::logic_error(
 
113
          _("Invalid revision tag; must be a number or a date"));
 
114
    }
 
115
  return os;
 
116
}
 
117
 
 
118
bool operator==(const svn_opt_revision_t& a,
 
119
                const svn_opt_revision_t& b)
 
120
{
 
121
  if (a.kind != b.kind)
 
122
    return false;
 
123
  if (a.kind == svn_opt_revision_number
 
124
      && a.value.number != b.value.number)
 
125
    return false;
 
126
  if (a.kind == svn_opt_revision_date
 
127
      && a.value.date != b.value.date)
 
128
    return false;
 
129
  return true;
 
130
}
 
131
 
 
132
inline bool operator!=(const svn_opt_revision_t& a,
 
133
                       const svn_opt_revision_t& b)
 
134
{
 
135
  return !(a == b);
 
136
}
 
137
 
 
138
class UnparseFunctor
 
139
{
 
140
public:
 
141
  explicit UnparseFunctor(std::ostringstream& buffer, bool old_format,
 
142
                          SVN::Pool& iterpool)
 
143
    : m_buffer(buffer),
 
144
      m_old_format(old_format),
 
145
      m_iterpool(iterpool)
 
146
    {}
 
147
 
 
148
  void operator()(const JavaHL::ExternalItem& item)
 
149
    {
 
150
      m_iterpool.clear();
 
151
 
 
152
      const Java::Env env(item.get_env());
 
153
      const Java::LocalFrame frame(env);
 
154
 
 
155
      if (!m_old_format)
 
156
        {
 
157
          if (item.revision()->kind != svn_opt_revision_head
 
158
              && *item.revision() != *item.peg_revision())
 
159
            {
 
160
              m_buffer << "-r"
 
161
                       << FormatRevision(item.revision(), m_iterpool)
 
162
                       << ' ';
 
163
            }
 
164
          if (item.peg_revision()->kind == svn_opt_revision_head)
 
165
            m_buffer << item.url() << ' ';
 
166
          else
 
167
            {
 
168
              m_buffer << item.url() << '@'
 
169
                       << FormatRevision(item.peg_revision(), m_iterpool)
 
170
                       << ' ';
 
171
            }
 
172
          m_buffer << item.target_dir() << '\n';
 
173
        }
 
174
      else
 
175
        {
 
176
          // Sanity check: old format does not support peg revisions
 
177
          if (item.peg_revision()->kind != svn_opt_revision_head
 
178
              && *item.revision() != *item.peg_revision())
 
179
            {
 
180
              JavaHL::SubversionException(env)
 
181
                .raise(_("Clients older than Subversion 1.5"
 
182
                         " do not support peg revision syntax"
 
183
                         " in the svn:externals property"));
 
184
            }
 
185
 
 
186
          // Sanity check: old format does not support relative URLs
 
187
          const std::string url = item.url();
 
188
          if (   (url.size() >= 1 && (url[0] == '.' || url[0] == '/'))
 
189
                 || (url.size() >= 2 && (url[0] == '^' && url[1] == '/')))
 
190
            {
 
191
              JavaHL::SubversionException(env)
 
192
                .raise(_("Clients older than Subversion 1.5"
 
193
                         " do not support relative URLs"
 
194
                         " in the svn:externals property"));
 
195
            }
 
196
 
 
197
          m_buffer << item.target_dir() << ' ';
 
198
          if (item.revision()->kind != svn_opt_revision_head)
 
199
            {
 
200
              m_buffer << "-r"
 
201
                       << FormatRevision(item.revision(), m_iterpool)
 
202
                       << ' ';
 
203
            }
 
204
          m_buffer << url << '\n';
 
205
        }
 
206
    }
 
207
 
 
208
private:
 
209
  std::ostringstream& m_buffer;
 
210
  const bool m_old_format;
 
211
  SVN::Pool& m_iterpool;
 
212
};
 
213
} // anoymous namespace
 
214
 
 
215
 
 
216
JNIEXPORT jbyteArray JNICALL
 
217
Java_org_apache_subversion_javahl_util_PropLib_checkNodeProp(
 
218
    JNIEnv* jenv, jobject jthis,
 
219
    jstring jname, jbyteArray jvalue, jstring jpath, jobject jkind,
 
220
    jstring jmime_type, jobject jfile_contents,
 
221
    jboolean jskip_some_checks)
 
222
{
 
223
  SVN_JAVAHL_JNI_TRY(PropLib, checkLocalProp)
 
224
    {
 
225
      const Java::Env env(jenv);
 
226
 
 
227
      const svn_node_kind_t kind = EnumMapper::toNodeKind(jkind);
 
228
      SVN_JAVAHL_OLDSTYLE_EXCEPTION_CHECK(env);
 
229
 
 
230
      const Java::String name_str(env, jname);
 
231
      const Java::ByteArray value(env, jvalue);
 
232
      const Java::String path_str(env, jpath);
 
233
      const Java::String mime_type_str(env, jmime_type);
 
234
      Java::InputStream file_contents(env, jfile_contents);
 
235
 
 
236
      // Using a "global" request pool since we don't keep a context
 
237
      // with its own pool around for these functions.
 
238
      SVN::Pool pool;
 
239
 
 
240
      const Java::String::Contents name(name_str);
 
241
      const Java::String::Contents path(path_str);
 
242
      const Java::String::Contents mime_type(mime_type_str);
 
243
      PropGetter getter(mime_type.c_str(), file_contents.get_stream(pool));
 
244
 
 
245
      const svn_string_t* canonval;
 
246
      SVN_JAVAHL_CHECK(env,
 
247
                       svn_wc_canonicalize_svn_prop(
 
248
                           &canonval, name.c_str(),
 
249
                           Java::ByteArray::Contents(value).get_string(pool),
 
250
                           path.c_str(), kind,
 
251
                           svn_boolean_t(jskip_some_checks),
 
252
                           PropGetter::callback, &getter,
 
253
                           pool.getPool()));
 
254
      return Java::ByteArray(env, canonval->data, jint(canonval->len)).get();
 
255
    }
 
256
  SVN_JAVAHL_JNI_CATCH;
 
257
  return NULL;
 
258
}
 
259
 
 
260
 
 
261
JNIEXPORT jobject JNICALL
 
262
Java_org_apache_subversion_javahl_util_PropLib_parseExternals(
 
263
    JNIEnv* jenv, jobject jthis,
 
264
    jbyteArray jdescription, jstring jparent_dir, jboolean jcanonicalize_url)
 
265
{
 
266
  SVN_JAVAHL_JNI_TRY(PropLib, parseExternals)
 
267
    {
 
268
      const Java::Env env(jenv);
 
269
 
 
270
      const Java::ByteArray description(env, jdescription);
 
271
      const Java::String parent_dir(env, jparent_dir);
 
272
 
 
273
      // Using a "global" request pool since we don't keep a context
 
274
      // with its own pool around for these functions.
 
275
      SVN::Pool pool;
 
276
 
 
277
      apr_array_header_t* externals;
 
278
      {
 
279
        // There is no guarantee that the description contents are
 
280
        // null-terminated. Copy them to an svn_string_t to make sure
 
281
        // that they are.
 
282
        svn_string_t* const description_contents =
 
283
          Java::ByteArray::Contents(description).get_string(pool);
 
284
 
 
285
        SVN_JAVAHL_CHECK(env,
 
286
                         svn_wc_parse_externals_description3(
 
287
                             &externals,
 
288
                             Java::String::Contents(parent_dir).c_str(),
 
289
                             description_contents->data,
 
290
                             svn_boolean_t(jcanonicalize_url),
 
291
                             pool.getPool()));
 
292
      }
 
293
 
 
294
      Java::List<JavaHL::ExternalItem> items(env, externals->nelts);
 
295
      for (jint i = 0; i < externals->nelts; ++i)
 
296
        {
 
297
          // References to the newly created external items are stored
 
298
          // in the list, so make sure the local reference in this
 
299
          // frame get cleared on each iteration.
 
300
          Java::LocalFrame frame;
 
301
 
 
302
          const svn_wc_external_item2_t* const item =
 
303
            APR_ARRAY_IDX(externals, i, svn_wc_external_item2_t*);
 
304
          items.add(JavaHL::ExternalItem(env,
 
305
                                         item->target_dir,
 
306
                                         item->url,
 
307
                                         &item->revision,
 
308
                                         &item->peg_revision));
 
309
        }
 
310
      return items.get();
 
311
    }
 
312
  SVN_JAVAHL_JNI_CATCH;
 
313
  return NULL;
 
314
}
 
315
 
 
316
 
 
317
JNIEXPORT jbyteArray JNICALL
 
318
Java_org_apache_subversion_javahl_util_PropLib_unparseExternals(
 
319
    JNIEnv* jenv, jobject jthis,
 
320
    jobject jitems, jstring jparent_dir, jboolean jold_format)
 
321
{
 
322
  SVN_JAVAHL_JNI_TRY(PropLib, unparseExternals)
 
323
    {
 
324
      const Java::Env env(jenv);
 
325
 
 
326
      const Java::ImmutableList<JavaHL::ExternalItem> items(env, jitems);
 
327
      const Java::String parent_dir(env, jparent_dir);
 
328
 
 
329
      // Using a "global" iteration pool since we don't keep a context
 
330
      // with its own pool around for these functions.
 
331
      SVN::Pool iterpool;
 
332
 
 
333
      std::ostringstream buffer;
 
334
      items.for_each(UnparseFunctor(buffer, jold_format, iterpool));
 
335
      const std::string description(buffer.str());
 
336
 
 
337
      // Validate the result. Even though we generated the string
 
338
      // ourselves, we did not validate the input paths and URLs.
 
339
      SVN_JAVAHL_CHECK(env,
 
340
                       svn_wc_parse_externals_description3(
 
341
                           NULL,
 
342
                           Java::String::Contents(parent_dir).c_str(),
 
343
                           description.c_str(),
 
344
                           false, iterpool.getPool()));
 
345
      return Java::ByteArray(env, description).get();
 
346
    }
 
347
  SVN_JAVAHL_JNI_CATCH;
 
348
  return NULL;
 
349
}
 
350
 
 
351
 
 
352
JNIEXPORT jstring JNICALL
 
353
Java_org_apache_subversion_javahl_util_PropLib_resolveExternalsUrl(
 
354
    JNIEnv* jenv, jobject jthis,
 
355
    jobject jitem, jstring jrepos_root_url, jstring jparent_dir_url)
 
356
{
 
357
  SVN_JAVAHL_JNI_TRY(PropLib, unparseExternals)
 
358
    {
 
359
      const Java::Env env(jenv);
 
360
 
 
361
      const Java::String repos_root_url(env, jrepos_root_url);
 
362
      const Java::String parent_dir_url(env, jparent_dir_url);
 
363
      const JavaHL::ExternalItem item(env, jitem);
 
364
 
 
365
      // Using a "global" request pool since we don't keep a context
 
366
      // with its own pool around for these functions.
 
367
      SVN::Pool pool;
 
368
 
 
369
      const char* resolved_url;
 
370
      SVN_JAVAHL_CHECK(env,
 
371
                       svn_wc__resolve_relative_external_url(
 
372
                           &resolved_url,
 
373
                           item.get_external_item(pool),
 
374
                           Java::String::Contents(repos_root_url).c_str(),
 
375
                           Java::String::Contents(parent_dir_url).c_str(),
 
376
                           pool.getPool(), pool.getPool()));
 
377
      return Java::String(env, resolved_url).get();
 
378
    }
 
379
  SVN_JAVAHL_JNI_CATCH;
 
380
  return NULL;
 
381
}