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