]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_subr/macos_keychain.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_subr / macos_keychain.c
1 /*
2  * macos_keychain.c: Mac OS keychain providers for SVN_AUTH_*
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 /* ==================================================================== */
25
26 /*** Includes. ***/
27
28 #include <apr_pools.h>
29 #include "svn_auth.h"
30 #include "svn_error.h"
31 #include "svn_utf.h"
32 #include "svn_config.h"
33 #include "svn_user.h"
34
35 #include "private/svn_auth_private.h"
36
37 #include "svn_private_config.h"
38
39 #ifdef SVN_HAVE_KEYCHAIN_SERVICES
40
41 #include <Security/Security.h>
42 \f
43 /*-----------------------------------------------------------------------*/
44 /* keychain simple provider, puts passwords in the KeyChain              */
45 /*-----------------------------------------------------------------------*/
46
47 /*
48  * XXX (2005-12-07): If no GUI is available (e.g. over a SSH session),
49  * you won't be prompted for credentials with which to unlock your
50  * keychain.  Apple recognizes lack of TTY prompting as a known
51  * problem.
52  *
53  *
54  * XXX (2005-12-07): SecKeychainSetUserInteractionAllowed(FALSE) does
55  * not appear to actually prevent all user interaction.  Specifically,
56  * if the executable changes (for example, if it is rebuilt), the
57  * system prompts the user to okay the use of the new executable.
58  *
59  * Worse than that, the interactivity setting is global per app (not
60  * process/thread), meaning that there is a race condition in the
61  * implementation below between calls to
62  * SecKeychainSetUserInteractionAllowed() when multiple instances of
63  * the same Subversion auth provider-based app run concurrently.
64  */
65
66 /* Implementation of svn_auth__password_set_t that stores
67    the password in the OS X KeyChain. */
68 static svn_error_t *
69 keychain_password_set(svn_boolean_t *done,
70                       apr_hash_t *creds,
71                       const char *realmstring,
72                       const char *username,
73                       const char *password,
74                       apr_hash_t *parameters,
75                       svn_boolean_t non_interactive,
76                       apr_pool_t *pool)
77 {
78   OSStatus status;
79   SecKeychainItemRef item;
80
81   if (non_interactive)
82     SecKeychainSetUserInteractionAllowed(FALSE);
83
84   status = SecKeychainFindGenericPassword(NULL, (int) strlen(realmstring),
85                                           realmstring, username == NULL
86                                             ? 0
87                                             : (int) strlen(username),
88                                           username, 0, NULL, &item);
89   if (status)
90     {
91       if (status == errSecItemNotFound)
92         status = SecKeychainAddGenericPassword(NULL, (int) strlen(realmstring),
93                                                realmstring, username == NULL
94                                                  ? 0
95                                                  : (int) strlen(username),
96                                                username, (int) strlen(password),
97                                                password, NULL);
98     }
99   else
100     {
101       status = SecKeychainItemModifyAttributesAndData(item, NULL,
102                                                       (int) strlen(password),
103                                                       password);
104       CFRelease(item);
105     }
106
107   if (non_interactive)
108     SecKeychainSetUserInteractionAllowed(TRUE);
109
110   *done = (status == 0);
111
112   return SVN_NO_ERROR;
113 }
114
115 /* Implementation of svn_auth__password_get_t that retrieves
116    the password from the OS X KeyChain. */
117 static svn_error_t *
118 keychain_password_get(svn_boolean_t *done,
119                       const char **password,
120                       apr_hash_t *creds,
121                       const char *realmstring,
122                       const char *username,
123                       apr_hash_t *parameters,
124                       svn_boolean_t non_interactive,
125                       apr_pool_t *pool)
126 {
127   OSStatus status;
128   UInt32 length;
129   void *data;
130
131   *done = FALSE;
132
133   if (non_interactive)
134     SecKeychainSetUserInteractionAllowed(FALSE);
135
136   status = SecKeychainFindGenericPassword(NULL, (int) strlen(realmstring),
137                                           realmstring, username == NULL
138                                             ? 0
139                                             : (int) strlen(username),
140                                           username, &length, &data, NULL);
141
142   if (non_interactive)
143     SecKeychainSetUserInteractionAllowed(TRUE);
144
145   if (status != 0)
146     return SVN_NO_ERROR;
147
148   *password = apr_pstrmemdup(pool, data, length);
149   SecKeychainItemFreeContent(NULL, data);
150   *done = TRUE;
151   return SVN_NO_ERROR;
152 }
153
154 /* Get cached encrypted credentials from the simple provider's cache. */
155 static svn_error_t *
156 keychain_simple_first_creds(void **credentials,
157                             void **iter_baton,
158                             void *provider_baton,
159                             apr_hash_t *parameters,
160                             const char *realmstring,
161                             apr_pool_t *pool)
162 {
163   return svn_auth__simple_creds_cache_get(credentials,
164                                           iter_baton,
165                                           provider_baton,
166                                           parameters,
167                                           realmstring,
168                                           keychain_password_get,
169                                           SVN_AUTH__KEYCHAIN_PASSWORD_TYPE,
170                                           pool);
171 }
172
173 /* Save encrypted credentials to the simple provider's cache. */
174 static svn_error_t *
175 keychain_simple_save_creds(svn_boolean_t *saved,
176                            void *credentials,
177                            void *provider_baton,
178                            apr_hash_t *parameters,
179                            const char *realmstring,
180                            apr_pool_t *pool)
181 {
182   return svn_auth__simple_creds_cache_set(saved, credentials,
183                                           provider_baton,
184                                           parameters,
185                                           realmstring,
186                                           keychain_password_set,
187                                           SVN_AUTH__KEYCHAIN_PASSWORD_TYPE,
188                                           pool);
189 }
190
191 static const svn_auth_provider_t keychain_simple_provider = {
192   SVN_AUTH_CRED_SIMPLE,
193   keychain_simple_first_creds,
194   NULL,
195   keychain_simple_save_creds
196 };
197
198 /* Get cached encrypted credentials from the ssl client cert password
199    provider's cache. */
200 static svn_error_t *
201 keychain_ssl_client_cert_pw_first_creds(void **credentials,
202                                         void **iter_baton,
203                                         void *provider_baton,
204                                         apr_hash_t *parameters,
205                                         const char *realmstring,
206                                         apr_pool_t *pool)
207 {
208   return svn_auth__ssl_client_cert_pw_cache_get(credentials,
209                                                 iter_baton, provider_baton,
210                                                 parameters, realmstring,
211                                                 keychain_password_get,
212                                                 SVN_AUTH__KEYCHAIN_PASSWORD_TYPE,
213                                                 pool);
214 }
215
216 /* Save encrypted credentials to the ssl client cert password provider's
217    cache. */
218 static svn_error_t *
219 keychain_ssl_client_cert_pw_save_creds(svn_boolean_t *saved,
220                                        void *credentials,
221                                        void *provider_baton,
222                                        apr_hash_t *parameters,
223                                        const char *realmstring,
224                                        apr_pool_t *pool)
225 {
226   return svn_auth__ssl_client_cert_pw_cache_set(saved, credentials,
227                                                 provider_baton, parameters,
228                                                 realmstring,
229                                                 keychain_password_set,
230                                                 SVN_AUTH__KEYCHAIN_PASSWORD_TYPE,
231                                                 pool);
232 }
233
234 static const svn_auth_provider_t keychain_ssl_client_cert_pw_provider = {
235   SVN_AUTH_CRED_SSL_CLIENT_CERT_PW,
236   keychain_ssl_client_cert_pw_first_creds,
237   NULL,
238   keychain_ssl_client_cert_pw_save_creds
239 };
240
241
242 /* Public API */
243 void
244 svn_auth_get_keychain_simple_provider(svn_auth_provider_object_t **provider,
245                                       apr_pool_t *pool)
246 {
247   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
248
249   po->vtable = &keychain_simple_provider;
250   *provider = po;
251 }
252
253 void
254 svn_auth_get_keychain_ssl_client_cert_pw_provider
255   (svn_auth_provider_object_t **provider,
256    apr_pool_t *pool)
257 {
258   svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po));
259
260   po->vtable = &keychain_ssl_client_cert_pw_provider;
261   *provider = po;
262 }
263 #endif /* SVN_HAVE_KEYCHAIN_SERVICES */