1251881Speter/*
2251881Speter * ssl_server_trust_providers.c: providers for
3251881Speter * SVN_AUTH_CRED_SSL_SERVER_TRUST
4251881Speter *
5251881Speter * ====================================================================
6251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
7251881Speter *    or more contributor license agreements.  See the NOTICE file
8251881Speter *    distributed with this work for additional information
9251881Speter *    regarding copyright ownership.  The ASF licenses this file
10251881Speter *    to you under the Apache License, Version 2.0 (the
11251881Speter *    "License"); you may not use this file except in compliance
12251881Speter *    with the License.  You may obtain a copy of the License at
13251881Speter *
14251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
15251881Speter *
16251881Speter *    Unless required by applicable law or agreed to in writing,
17251881Speter *    software distributed under the License is distributed on an
18251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19251881Speter *    KIND, either express or implied.  See the License for the
20251881Speter *    specific language governing permissions and limitations
21251881Speter *    under the License.
22251881Speter * ====================================================================
23251881Speter */
24251881Speter
25251881Speter#include <apr_pools.h>
26251881Speter
27251881Speter#include "svn_hash.h"
28251881Speter#include "svn_auth.h"
29251881Speter#include "svn_error.h"
30251881Speter#include "svn_config.h"
31251881Speter#include "svn_string.h"
32251881Speter
33251881Speter
34251881Speter/*-----------------------------------------------------------------------*/
35251881Speter/* File provider                                                         */
36251881Speter/*-----------------------------------------------------------------------*/
37251881Speter
38251881Speter/* The keys that will be stored on disk.  These serve the same role as
39251881Speter   similar constants in other providers. */
40251881Speter#define AUTHN_ASCII_CERT_KEY            "ascii_cert"
41251881Speter#define AUTHN_FAILURES_KEY              "failures"
42251881Speter
43251881Speter
44251881Speter/* retrieve ssl server CA failure overrides (if any) from servers
45251881Speter   config */
46251881Speterstatic svn_error_t *
47251881Speterssl_server_trust_file_first_credentials(void **credentials,
48251881Speter                                        void **iter_baton,
49251881Speter                                        void *provider_baton,
50251881Speter                                        apr_hash_t *parameters,
51251881Speter                                        const char *realmstring,
52251881Speter                                        apr_pool_t *pool)
53251881Speter{
54251881Speter  apr_uint32_t *failures = svn_hash_gets(parameters,
55251881Speter                                         SVN_AUTH_PARAM_SSL_SERVER_FAILURES);
56251881Speter  const svn_auth_ssl_server_cert_info_t *cert_info =
57251881Speter    svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO);
58251881Speter  apr_hash_t *creds_hash = NULL;
59251881Speter  const char *config_dir;
60251881Speter  svn_error_t *error = SVN_NO_ERROR;
61251881Speter
62251881Speter  *credentials = NULL;
63251881Speter  *iter_baton = NULL;
64251881Speter
65251881Speter  /* Check if this is a permanently accepted certificate */
66251881Speter  config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
67251881Speter  error =
68251881Speter    svn_config_read_auth_data(&creds_hash, SVN_AUTH_CRED_SSL_SERVER_TRUST,
69251881Speter                              realmstring, config_dir, pool);
70251881Speter  svn_error_clear(error);
71251881Speter  if (! error && creds_hash)
72251881Speter    {
73251881Speter      svn_string_t *trusted_cert, *this_cert, *failstr;
74251881Speter      apr_uint32_t last_failures = 0;
75251881Speter
76251881Speter      trusted_cert = svn_hash_gets(creds_hash, AUTHN_ASCII_CERT_KEY);
77251881Speter      this_cert = svn_string_create(cert_info->ascii_cert, pool);
78251881Speter      failstr = svn_hash_gets(creds_hash, AUTHN_FAILURES_KEY);
79251881Speter
80251881Speter      if (failstr)
81251881Speter        {
82251881Speter          char *endptr;
83251881Speter          unsigned long tmp_ulong = strtoul(failstr->data, &endptr, 10);
84251881Speter
85251881Speter          if (*endptr == '\0')
86251881Speter            last_failures = (apr_uint32_t) tmp_ulong;
87251881Speter        }
88251881Speter
89251881Speter      /* If the cert is trusted and there are no new failures, we
90251881Speter       * accept it by clearing all failures. */
91251881Speter      if (trusted_cert &&
92251881Speter          svn_string_compare(this_cert, trusted_cert) &&
93251881Speter          (*failures & ~last_failures) == 0)
94251881Speter        {
95251881Speter          *failures = 0;
96251881Speter        }
97251881Speter    }
98251881Speter
99251881Speter  /* If all failures are cleared now, we return the creds */
100251881Speter  if (! *failures)
101251881Speter    {
102251881Speter      svn_auth_cred_ssl_server_trust_t *creds =
103251881Speter        apr_pcalloc(pool, sizeof(*creds));
104251881Speter      creds->may_save = FALSE; /* No need to save it again... */
105251881Speter      *credentials = creds;
106251881Speter    }
107251881Speter
108251881Speter  return SVN_NO_ERROR;
109251881Speter}
110251881Speter
111251881Speter
112251881Speterstatic svn_error_t *
113251881Speterssl_server_trust_file_save_credentials(svn_boolean_t *saved,
114251881Speter                                       void *credentials,
115251881Speter                                       void *provider_baton,
116251881Speter                                       apr_hash_t *parameters,
117251881Speter                                       const char *realmstring,
118251881Speter                                       apr_pool_t *pool)
119251881Speter{
120251881Speter  svn_auth_cred_ssl_server_trust_t *creds = credentials;
121251881Speter  const svn_auth_ssl_server_cert_info_t *cert_info;
122251881Speter  apr_hash_t *creds_hash = NULL;
123251881Speter  const char *config_dir;
124251881Speter
125251881Speter  if (! creds->may_save)
126251881Speter    return SVN_NO_ERROR;
127251881Speter
128251881Speter  config_dir = svn_hash_gets(parameters, SVN_AUTH_PARAM_CONFIG_DIR);
129251881Speter
130251881Speter  cert_info = svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO);
131251881Speter
132251881Speter  creds_hash = apr_hash_make(pool);
133251881Speter  svn_hash_sets(creds_hash, AUTHN_ASCII_CERT_KEY,
134251881Speter                svn_string_create(cert_info->ascii_cert, pool));
135251881Speter  svn_hash_sets(creds_hash,
136251881Speter                AUTHN_FAILURES_KEY,
137251881Speter                svn_string_createf(pool, "%lu",
138251881Speter                                   (unsigned long)creds->accepted_failures));
139251881Speter
140251881Speter  SVN_ERR(svn_config_write_auth_data(creds_hash,
141251881Speter                                     SVN_AUTH_CRED_SSL_SERVER_TRUST,
142251881Speter                                     realmstring,
143251881Speter                                     config_dir,
144251881Speter                                     pool));
145251881Speter  *saved = TRUE;
146251881Speter  return SVN_NO_ERROR;
147251881Speter}
148251881Speter
149251881Speter
150251881Speterstatic const svn_auth_provider_t ssl_server_trust_file_provider = {
151251881Speter  SVN_AUTH_CRED_SSL_SERVER_TRUST,
152251881Speter  &ssl_server_trust_file_first_credentials,
153251881Speter  NULL,
154251881Speter  &ssl_server_trust_file_save_credentials,
155251881Speter};
156251881Speter
157251881Speter
158251881Speter/*** Public API to SSL file providers. ***/
159251881Spetervoid
160251881Spetersvn_auth_get_ssl_server_trust_file_provider
161251881Speter  (svn_auth_provider_object_t **provider, apr_pool_t *pool)
162251881Speter{
163251881Speter  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
164251881Speter
165251881Speter  po->vtable = &ssl_server_trust_file_provider;
166251881Speter  *provider = po;
167251881Speter}
168251881Speter
169251881Speter
170251881Speter/*-----------------------------------------------------------------------*/
171251881Speter/* Prompt provider                                                       */
172251881Speter/*-----------------------------------------------------------------------*/
173251881Speter
174251881Speter/* Baton type for prompting to verify server ssl creds.
175251881Speter   There is no iteration baton type. */
176251881Spetertypedef struct ssl_server_trust_prompt_provider_baton_t
177251881Speter{
178251881Speter  svn_auth_ssl_server_trust_prompt_func_t prompt_func;
179251881Speter  void *prompt_baton;
180251881Speter} ssl_server_trust_prompt_provider_baton_t;
181251881Speter
182251881Speter
183251881Speterstatic svn_error_t *
184251881Speterssl_server_trust_prompt_first_cred(void **credentials_p,
185251881Speter                                   void **iter_baton,
186251881Speter                                   void *provider_baton,
187251881Speter                                   apr_hash_t *parameters,
188251881Speter                                   const char *realmstring,
189251881Speter                                   apr_pool_t *pool)
190251881Speter{
191251881Speter  ssl_server_trust_prompt_provider_baton_t *pb = provider_baton;
192251881Speter  apr_uint32_t *failures = svn_hash_gets(parameters,
193251881Speter                                         SVN_AUTH_PARAM_SSL_SERVER_FAILURES);
194251881Speter  const char *no_auth_cache = svn_hash_gets(parameters,
195251881Speter                                            SVN_AUTH_PARAM_NO_AUTH_CACHE);
196251881Speter  const svn_auth_ssl_server_cert_info_t *cert_info =
197251881Speter    svn_hash_gets(parameters, SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO);
198251881Speter  svn_boolean_t may_save = (!no_auth_cache
199251881Speter                            && !(*failures & SVN_AUTH_SSL_OTHER));
200251881Speter
201251881Speter  SVN_ERR(pb->prompt_func((svn_auth_cred_ssl_server_trust_t **)credentials_p,
202251881Speter                          pb->prompt_baton, realmstring, *failures, cert_info,
203251881Speter                          may_save, pool));
204251881Speter
205251881Speter  *iter_baton = NULL;
206251881Speter  return SVN_NO_ERROR;
207251881Speter}
208251881Speter
209251881Speter
210251881Speterstatic const svn_auth_provider_t ssl_server_trust_prompt_provider = {
211251881Speter  SVN_AUTH_CRED_SSL_SERVER_TRUST,
212251881Speter  ssl_server_trust_prompt_first_cred,
213251881Speter  NULL,
214251881Speter  NULL
215251881Speter};
216251881Speter
217251881Speter
218251881Speter/*** Public API to SSL prompting providers. ***/
219251881Spetervoid
220251881Spetersvn_auth_get_ssl_server_trust_prompt_provider
221251881Speter  (svn_auth_provider_object_t **provider,
222251881Speter   svn_auth_ssl_server_trust_prompt_func_t prompt_func,
223251881Speter   void *prompt_baton,
224251881Speter   apr_pool_t *pool)
225251881Speter{
226251881Speter  svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
227251881Speter  ssl_server_trust_prompt_provider_baton_t *pb =
228251881Speter    apr_palloc(pool, sizeof(*pb));
229251881Speter  pb->prompt_func = prompt_func;
230251881Speter  pb->prompt_baton = prompt_baton;
231251881Speter  po->vtable = &ssl_server_trust_prompt_provider;
232251881Speter  po->provider_baton = pb;
233251881Speter  *provider = po;
234251881Speter}
235