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

« back to all changes in this revision

Viewing changes to subversion/svn/auth-cmd.c

  • 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
 * auth-cmd.c:  Subversion auth creds cache administration
 
3
 *
 
4
 * ====================================================================
 
5
 *    Licensed to the Apache Software Foundation (ASF) under one
 
6
 *    or more contributor license agreements.  See the NOTICE file
 
7
 *    distributed with this work for additional information
 
8
 *    regarding copyright ownership.  The ASF licenses this file
 
9
 *    to you under the Apache License, Version 2.0 (the
 
10
 *    "License"); you may not use this file except in compliance
 
11
 *    with the License.  You may obtain a copy of the License at
 
12
 *
 
13
 *      http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
15
 *    Unless required by applicable law or agreed to in writing,
 
16
 *    software distributed under the License is distributed on an
 
17
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
18
 *    KIND, either express or implied.  See the License for the
 
19
 *    specific language governing permissions and limitations
 
20
 *    under the License.
 
21
 * ====================================================================
 
22
 */
 
23
 
 
24
/*** Includes. ***/
 
25
 
 
26
#include <apr_general.h>
 
27
#include <apr_getopt.h>
 
28
#include <apr_fnmatch.h>
 
29
#include <apr_tables.h>
 
30
 
 
31
#include "svn_private_config.h"
 
32
 
 
33
#include "svn_private_config.h"
 
34
#include "svn_pools.h"
 
35
#include "svn_error.h"
 
36
#include "svn_opt.h"
 
37
#include "svn_dirent_uri.h"
 
38
#include "svn_hash.h"
 
39
#include "svn_utf.h"
 
40
#include "svn_cmdline.h"
 
41
#include "svn_config.h"
 
42
#include "svn_auth.h"
 
43
#include "svn_sorts.h"
 
44
#include "svn_base64.h"
 
45
#include "svn_x509.h"
 
46
#include "svn_time.h"
 
47
 
 
48
#include "private/svn_cmdline_private.h"
 
49
#include "private/svn_token.h"
 
50
#include "private/svn_sorts_private.h"
 
51
 
 
52
#include "cl.h"
 
53
 
 
54
/* The separator between credentials . */
 
55
#define SEP_STRING \
 
56
  "------------------------------------------------------------------------\n"
 
57
 
 
58
static svn_error_t *
 
59
show_cert_failures(const char *failure_string,
 
60
                   apr_pool_t *scratch_pool)
 
61
{
 
62
  unsigned int failures;
 
63
 
 
64
  SVN_ERR(svn_cstring_atoui(&failures, failure_string));
 
65
 
 
66
  if (0 == (failures & (SVN_AUTH_SSL_NOTYETVALID | SVN_AUTH_SSL_EXPIRED |
 
67
                        SVN_AUTH_SSL_CNMISMATCH | SVN_AUTH_SSL_UNKNOWNCA |
 
68
                        SVN_AUTH_SSL_OTHER)))
 
69
    return SVN_NO_ERROR;
 
70
 
 
71
  SVN_ERR(svn_cmdline_printf(
 
72
            scratch_pool, _("Automatic certificate validity check failed "
 
73
                            "because:\n")));
 
74
 
 
75
  if (failures & SVN_AUTH_SSL_NOTYETVALID)
 
76
    SVN_ERR(svn_cmdline_printf(
 
77
              scratch_pool, _("  The certificate is not yet valid.\n")));
 
78
 
 
79
  if (failures & SVN_AUTH_SSL_EXPIRED)
 
80
    SVN_ERR(svn_cmdline_printf(
 
81
              scratch_pool, _("  The certificate has expired.\n")));
 
82
 
 
83
  if (failures & SVN_AUTH_SSL_CNMISMATCH)
 
84
    SVN_ERR(svn_cmdline_printf(
 
85
              scratch_pool, _("  The certificate's Common Name (hostname) "
 
86
                              "does not match the remote hostname.\n")));
 
87
 
 
88
  if (failures & SVN_AUTH_SSL_UNKNOWNCA)
 
89
    SVN_ERR(svn_cmdline_printf(
 
90
              scratch_pool, _("  The certificate issuer is unknown.\n")));
 
91
 
 
92
  if (failures & SVN_AUTH_SSL_OTHER)
 
93
    SVN_ERR(svn_cmdline_printf(
 
94
              scratch_pool, _("  Unknown verification failure.\n")));
 
95
 
 
96
  return SVN_NO_ERROR;
 
97
}
 
98
 
 
99
 
 
100
/* decodes from format we store certs in for auth creds and
 
101
 * turns parsing errors into warnings if PRINT_WARNING is TRUE
 
102
 * and ignores them otherwise. returns NULL if it couldn't
 
103
 * parse a cert for any reason. */
 
104
static svn_x509_certinfo_t *
 
105
parse_certificate(const svn_string_t *ascii_cert,
 
106
                  svn_boolean_t print_warning,
 
107
                  apr_pool_t *result_pool,
 
108
                  apr_pool_t *scratch_pool)
 
109
{
 
110
  svn_x509_certinfo_t *certinfo;
 
111
  const svn_string_t *der_cert;
 
112
  svn_error_t *err;
 
113
 
 
114
  /* Convert header-less PEM to DER by undoing base64 encoding. */
 
115
  der_cert = svn_base64_decode_string(ascii_cert, scratch_pool);
 
116
 
 
117
  err = svn_x509_parse_cert(&certinfo, der_cert->data, der_cert->len,
 
118
                            result_pool, scratch_pool);
 
119
  if (err)
 
120
    {
 
121
      /* Just display X.509 parsing errors as warnings and continue */
 
122
      if (print_warning)
 
123
        svn_handle_warning2(stderr, err, "svn: ");
 
124
      svn_error_clear(err);
 
125
      return NULL;
 
126
    }
 
127
 
 
128
  return certinfo;
 
129
}
 
130
 
 
131
 
 
132
struct walk_credentials_baton_t
 
133
{
 
134
  int matches;
 
135
  svn_boolean_t list;
 
136
  svn_boolean_t delete;
 
137
  svn_boolean_t show_passwords;
 
138
  apr_array_header_t *patterns;
 
139
};
 
140
 
 
141
static svn_boolean_t
 
142
match_pattern(const char *pattern, const char *value,
 
143
              svn_boolean_t caseblind, apr_pool_t *scratch_pool)
 
144
{
 
145
  const char *p = apr_psprintf(scratch_pool, "*%s*", pattern);
 
146
  int flags = (caseblind ? APR_FNM_CASE_BLIND : 0);
 
147
 
 
148
  return (apr_fnmatch(p, value, flags) == APR_SUCCESS);
 
149
}
 
150
 
 
151
static svn_boolean_t
 
152
match_certificate(svn_x509_certinfo_t **certinfo,
 
153
                  const char *pattern,
 
154
                  const svn_string_t *ascii_cert,
 
155
                  apr_pool_t *result_pool,
 
156
                  apr_pool_t *scratch_pool)
 
157
{
 
158
  const char *value;
 
159
  const svn_checksum_t *checksum;
 
160
  const apr_array_header_t *hostnames;
 
161
  int i;
 
162
 
 
163
  *certinfo = parse_certificate(ascii_cert, FALSE, result_pool, scratch_pool);
 
164
  if (*certinfo == NULL)
 
165
    return FALSE;
 
166
 
 
167
  value = svn_x509_certinfo_get_subject(*certinfo, scratch_pool);
 
168
  if (match_pattern(pattern, value, FALSE, scratch_pool))
 
169
    return TRUE;
 
170
 
 
171
  value = svn_x509_certinfo_get_issuer(*certinfo, scratch_pool);
 
172
  if (match_pattern(pattern, value, FALSE, scratch_pool))
 
173
    return TRUE;
 
174
 
 
175
  checksum = svn_x509_certinfo_get_digest(*certinfo);
 
176
  value = svn_checksum_to_cstring_display(checksum, scratch_pool);
 
177
  if (match_pattern(pattern, value, TRUE, scratch_pool))
 
178
    return TRUE;
 
179
 
 
180
  hostnames = svn_x509_certinfo_get_hostnames(*certinfo);
 
181
  if (hostnames)
 
182
    {
 
183
      for (i = 0; i < hostnames->nelts; i++)
 
184
        {
 
185
          const char *hostname = APR_ARRAY_IDX(hostnames, i, const char *);
 
186
          if (match_pattern(pattern, hostname, TRUE, scratch_pool))
 
187
            return TRUE;
 
188
        }
 
189
    }
 
190
 
 
191
  return FALSE;
 
192
}
 
193
 
 
194
 
 
195
static svn_error_t *
 
196
match_credential(svn_boolean_t *match,
 
197
                 svn_x509_certinfo_t **certinfo,
 
198
                 const char *cred_kind,
 
199
                 const char *realmstring,
 
200
                 apr_array_header_t *patterns,
 
201
                 apr_array_header_t *cred_items,
 
202
                 apr_pool_t *result_pool,
 
203
                 apr_pool_t *scratch_pool)
 
204
{
 
205
  int i;
 
206
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
207
 
 
208
  *match = FALSE;
 
209
 
 
210
  for (i = 0; i < patterns->nelts; i++)
 
211
    {
 
212
      const char *pattern = APR_ARRAY_IDX(patterns, i, const char *);
 
213
      int j;
 
214
 
 
215
      *match = match_pattern(pattern, cred_kind, FALSE, iterpool);
 
216
      if (!*match)
 
217
        *match = match_pattern(pattern, realmstring, FALSE, iterpool);
 
218
      if (!*match)
 
219
        {
 
220
          svn_pool_clear(iterpool);
 
221
          for (j = 0; j < cred_items->nelts; j++)
 
222
            {
 
223
              svn_sort__item_t item;
 
224
              const char *key;
 
225
              svn_string_t *value;
 
226
 
 
227
              item = APR_ARRAY_IDX(cred_items, j, svn_sort__item_t);
 
228
              key = item.key;
 
229
              value = item.value;
 
230
              if (strcmp(key, SVN_CONFIG_AUTHN_PASSWORD_KEY) == 0 ||
 
231
                  strcmp(key, SVN_CONFIG_AUTHN_PASSPHRASE_KEY) == 0)
 
232
                continue; /* don't match secrets */
 
233
              else if (strcmp(key, SVN_CONFIG_AUTHN_ASCII_CERT_KEY) == 0)
 
234
                *match = match_certificate(certinfo, pattern, value,
 
235
                                           result_pool, iterpool);
 
236
              else
 
237
                *match = match_pattern(pattern, value->data, FALSE, iterpool);
 
238
 
 
239
              if (*match)
 
240
                break;
 
241
            }
 
242
        }
 
243
      if (!*match)
 
244
        break;
 
245
    }
 
246
 
 
247
  return SVN_NO_ERROR;
 
248
}
 
249
 
 
250
static svn_error_t *
 
251
show_cert(svn_x509_certinfo_t *certinfo, const svn_string_t *pem_cert,
 
252
          apr_pool_t *scratch_pool)
 
253
{
 
254
  const apr_array_header_t *hostnames;
 
255
 
 
256
  if (certinfo == NULL)
 
257
    certinfo = parse_certificate(pem_cert, TRUE, scratch_pool, scratch_pool);
 
258
  if (certinfo == NULL)
 
259
    return SVN_NO_ERROR;
 
260
 
 
261
  SVN_ERR(svn_cmdline_printf(scratch_pool, _("Subject: %s\n"),
 
262
                             svn_x509_certinfo_get_subject(certinfo, scratch_pool)));
 
263
  SVN_ERR(svn_cmdline_printf(scratch_pool, _("Valid from: %s\n"),
 
264
                             svn_time_to_human_cstring(
 
265
                                 svn_x509_certinfo_get_valid_from(certinfo),
 
266
                                 scratch_pool)));
 
267
  SVN_ERR(svn_cmdline_printf(scratch_pool, _("Valid until: %s\n"),
 
268
                             svn_time_to_human_cstring(
 
269
                                 svn_x509_certinfo_get_valid_to(certinfo),
 
270
                                 scratch_pool)));
 
271
  SVN_ERR(svn_cmdline_printf(scratch_pool, _("Issuer: %s\n"),
 
272
                             svn_x509_certinfo_get_issuer(certinfo, scratch_pool)));
 
273
  SVN_ERR(svn_cmdline_printf(scratch_pool, _("Fingerprint: %s\n"),
 
274
                             svn_checksum_to_cstring_display(
 
275
                                 svn_x509_certinfo_get_digest(certinfo),
 
276
                                 scratch_pool)));
 
277
 
 
278
  hostnames = svn_x509_certinfo_get_hostnames(certinfo);
 
279
  if (hostnames && !apr_is_empty_array(hostnames))
 
280
    {
 
281
      int i;
 
282
      svn_stringbuf_t *buf = svn_stringbuf_create_empty(scratch_pool);
 
283
      for (i = 0; i < hostnames->nelts; ++i)
 
284
        {
 
285
          const char *hostname = APR_ARRAY_IDX(hostnames, i, const char*);
 
286
          if (i > 0)
 
287
            svn_stringbuf_appendbytes(buf, ", ", 2);
 
288
          svn_stringbuf_appendbytes(buf, hostname, strlen(hostname));
 
289
        }
 
290
      SVN_ERR(svn_cmdline_printf(scratch_pool, _("Hostnames: %s\n"),
 
291
                                 buf->data));
 
292
    }
 
293
 
 
294
  return SVN_NO_ERROR;
 
295
}
 
296
 
 
297
static svn_error_t *
 
298
list_credential(const char *cred_kind,
 
299
                const char *realmstring,
 
300
                apr_array_header_t *cred_items,
 
301
                svn_boolean_t show_passwords,
 
302
                svn_x509_certinfo_t *certinfo,
 
303
                apr_pool_t *scratch_pool)
 
304
{
 
305
  int i;
 
306
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
307
 
 
308
  SVN_ERR(svn_cmdline_printf(scratch_pool, SEP_STRING));
 
309
  SVN_ERR(svn_cmdline_printf(scratch_pool,
 
310
                             _("Credential kind: %s\n"), cred_kind));
 
311
  SVN_ERR(svn_cmdline_printf(scratch_pool,
 
312
                             _("Authentication realm: %s\n"), realmstring));
 
313
 
 
314
  for (i = 0; i < cred_items->nelts; i++)
 
315
    {
 
316
      svn_sort__item_t item;
 
317
      const char *key;
 
318
      svn_string_t *value;
 
319
 
 
320
      svn_pool_clear(iterpool);
 
321
      item = APR_ARRAY_IDX(cred_items, i, svn_sort__item_t);
 
322
      key = item.key;
 
323
      value = item.value;
 
324
      if (strcmp(value->data, realmstring) == 0)
 
325
        continue; /* realm string was already shown above */
 
326
      else if (strcmp(key, SVN_CONFIG_AUTHN_PASSWORD_KEY) == 0)
 
327
        {
 
328
          if (show_passwords)
 
329
            SVN_ERR(svn_cmdline_printf(iterpool,
 
330
                                       _("Password: %s\n"), value->data));
 
331
          else
 
332
            SVN_ERR(svn_cmdline_printf(iterpool, _("Password: [not shown]\n")));
 
333
        }
 
334
      else if (strcmp(key, SVN_CONFIG_AUTHN_PASSPHRASE_KEY) == 0)
 
335
        {
 
336
          if (show_passwords)
 
337
            SVN_ERR(svn_cmdline_printf(iterpool,
 
338
                                       _("Passphrase: %s\n"), value->data));
 
339
          else
 
340
            SVN_ERR(svn_cmdline_printf(iterpool,
 
341
                                       _("Passphrase: [not shown]\n")));
 
342
        }
 
343
      else if (strcmp(key, SVN_CONFIG_AUTHN_PASSTYPE_KEY) == 0)
 
344
        SVN_ERR(svn_cmdline_printf(iterpool, _("Password cache: %s\n"),
 
345
                                   value->data));
 
346
      else if (strcmp(key, SVN_CONFIG_AUTHN_USERNAME_KEY) == 0)
 
347
        SVN_ERR(svn_cmdline_printf(iterpool, _("Username: %s\n"), value->data));
 
348
      else if (strcmp(key, SVN_CONFIG_AUTHN_ASCII_CERT_KEY) == 0)
 
349
       SVN_ERR(show_cert(certinfo, value, iterpool));
 
350
      else if (strcmp(key, SVN_CONFIG_AUTHN_FAILURES_KEY) == 0)
 
351
        SVN_ERR(show_cert_failures(value->data, iterpool));
 
352
      else
 
353
        SVN_ERR(svn_cmdline_printf(iterpool, "%s: %s\n", key, value->data));
 
354
    }
 
355
  svn_pool_destroy(iterpool);
 
356
 
 
357
  SVN_ERR(svn_cmdline_printf(scratch_pool, "\n"));
 
358
  return SVN_NO_ERROR;
 
359
}
 
360
 
 
361
/* This implements `svn_config_auth_walk_func_t` */
 
362
static svn_error_t *
 
363
walk_credentials(svn_boolean_t *delete_cred,
 
364
                 void *baton,
 
365
                 const char *cred_kind,
 
366
                 const char *realmstring,
 
367
                 apr_hash_t *cred_hash,
 
368
                 apr_pool_t *scratch_pool)
 
369
{
 
370
  struct walk_credentials_baton_t *b = baton;
 
371
  apr_array_header_t *sorted_cred_items;
 
372
  svn_x509_certinfo_t *certinfo = NULL;
 
373
 
 
374
  *delete_cred = FALSE;
 
375
 
 
376
  sorted_cred_items = svn_sort__hash(cred_hash,
 
377
                                     svn_sort_compare_items_lexically,
 
378
                                     scratch_pool);
 
379
  if (b->patterns->nelts > 0)
 
380
    {
 
381
      svn_boolean_t match;
 
382
 
 
383
      SVN_ERR(match_credential(&match, &certinfo, cred_kind, realmstring,
 
384
                               b->patterns, sorted_cred_items,
 
385
                               scratch_pool, scratch_pool));
 
386
      if (!match)
 
387
        return SVN_NO_ERROR;
 
388
    }
 
389
 
 
390
  b->matches++;
 
391
 
 
392
  if (b->list)
 
393
    SVN_ERR(list_credential(cred_kind, realmstring, sorted_cred_items,
 
394
                            b->show_passwords, certinfo, scratch_pool));
 
395
  if (b->delete)
 
396
    {
 
397
      *delete_cred = TRUE;
 
398
      SVN_ERR(svn_cmdline_printf(scratch_pool,
 
399
                                 _("Deleting %s credential for realm '%s'\n"),
 
400
                                 cred_kind, realmstring));
 
401
    }
 
402
 
 
403
  return SVN_NO_ERROR;
 
404
}
 
405
 
 
406
 
 
407
/* This implements `svn_opt_subcommand_t'. */
 
408
svn_error_t *
 
409
svn_cl__auth(apr_getopt_t *os, void *baton, apr_pool_t *pool)
 
410
{
 
411
  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
 
412
  const char *config_path;
 
413
  struct walk_credentials_baton_t b;
 
414
 
 
415
  b.matches = 0;
 
416
  b.show_passwords = opt_state->show_passwords;
 
417
  b.list = !opt_state->remove;
 
418
  b.delete = opt_state->remove;
 
419
  b.patterns = apr_array_make(pool, 1, sizeof(const char *));
 
420
  for (; os->ind < os->argc; os->ind++)
 
421
    {
 
422
      /* The apr_getopt targets are still in native encoding. */
 
423
      const char *raw_target = os->argv[os->ind];
 
424
      const char *utf8_target;
 
425
 
 
426
      SVN_ERR(svn_utf_cstring_to_utf8(&utf8_target,
 
427
                                      raw_target, pool));
 
428
      APR_ARRAY_PUSH(b.patterns, const char *) = utf8_target;
 
429
    }
 
430
 
 
431
  SVN_ERR(svn_config_get_user_config_path(&config_path,
 
432
                                          opt_state->config_dir, NULL,
 
433
                                          pool));
 
434
 
 
435
  if (b.delete && b.patterns->nelts < 1)
 
436
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
 
437
 
 
438
  SVN_ERR(svn_config_walk_auth_data(config_path, walk_credentials, &b, pool));
 
439
 
 
440
  if (b.list)
 
441
    {
 
442
      if (b.matches == 0)
 
443
        {
 
444
          if (b.patterns->nelts == 0)
 
445
            SVN_ERR(svn_cmdline_printf(pool,
 
446
                      _("Credentials cache in '%s' is empty\n"),
 
447
                      svn_dirent_local_style(config_path, pool)));
 
448
          else
 
449
            return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, 0,
 
450
                                     _("Credentials cache in '%s' contains "
 
451
                                       "no matching credentials"),
 
452
                                     svn_dirent_local_style(config_path, pool));
 
453
        }
 
454
      else
 
455
        {
 
456
          if (b.patterns->nelts == 0)
 
457
            SVN_ERR(svn_cmdline_printf(pool,
 
458
                      _("Credentials cache in '%s' contains %d credentials\n"),
 
459
                      svn_dirent_local_style(config_path, pool), b.matches));
 
460
          else
 
461
            SVN_ERR(svn_cmdline_printf(pool,
 
462
                      _("Credentials cache in '%s' contains %d matching "
 
463
                        "credentials\n"),
 
464
                      svn_dirent_local_style(config_path, pool), b.matches));
 
465
        }
 
466
 
 
467
    }
 
468
 
 
469
  if (b.delete)
 
470
    {
 
471
      if (b.matches == 0)
 
472
        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, 0,
 
473
                                 _("Credentials cache in '%s' contains "
 
474
                                   "no matching credentials"),
 
475
                                 svn_dirent_local_style(config_path, pool));
 
476
      else
 
477
        SVN_ERR(svn_cmdline_printf(pool, _("Deleted %d matching credentials "
 
478
                                   "from '%s'\n"), b.matches,
 
479
                                   svn_dirent_local_style(config_path, pool)));
 
480
    }
 
481
 
 
482
  return SVN_NO_ERROR;
 
483
}