GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Files | Functions
GUIUtility

Files

file  gnc-keyring.h
 Functions to save and retrieve passwords.
 

Functions

void gnc_keyring_set_password (const gchar *access_method, const gchar *server, guint32 port, const gchar *service, const gchar *user, const gchar *password)
 
gboolean gnc_keyring_get_password (GtkWidget *parent, const gchar *access_method, const gchar *server, guint32 port, const gchar *service, gchar **user, gchar **password)
 

Detailed Description

Function Documentation

gboolean gnc_keyring_get_password ( GtkWidget *  parent,
const gchar *  access_method,
const gchar *  server,
guint32  port,
const gchar *  service,
gchar **  user,
gchar **  password 
)

Attempt to retrieve a password to connect to a remote service. This is deliberately generic: the remote service can be a database, website, anything.

If a trusted keystore infrastructure is found (such as the Gnome's keyring or Mac OS X' keychain) this infrastructure will be queried first.

If no such infrastructure is available or the query didn't return a valid result, the user will be prompted for his password.

Warning
When the user is prompted for a password, he can also change the username. So whenever you call this function, read both the username and password values before you continue !
Parameters
parentUsed to transition from in case the user is prompted for a password.
access_methodService type the user attempts to access. Can things like 'mysql', 'postgres' and so on.
serverServer the user wishes to connect to.
portPort the service listens on. If set to 0, it will be ignored in the search for a password.
serviceThe service the user wishes to access on the server. This can be a database name or a path.
userThe user name to access the service. Remember, although you pass it to search for the password, it can have changed when the function returns.
passwordThe password to access the service.
Returns
a boolean indicating whether or not a valid password has been retrieved. The function will return FALSE when the user explicitly cancels the password dialog or if it wasn't called properly. Otherwise it wil return TRUE.

access_method, server, port, service and user will be the parameters passed to the trusted keystore (if available) to find the unique password for this service.

Definition at line 146 of file gnc-keyring.c.

153 {
154  gboolean password_found = FALSE;
155 #ifdef HAVE_LIBSECRET
156  GError* error = NULL;
157  char* libsecret_password;
158 #endif
159 #if HAVE_GNOME_KEYRING
160  GnomeKeyringResult gkr_result;
161  GList *found_list = NULL;
162  GnomeKeyringNetworkPasswordData *found;
163 #endif
164 #ifdef HAVE_OSX_KEYCHAIN
165  void *password_data;
166  UInt32 password_length;
167  OSStatus status;
168 #endif
169 
170  g_return_val_if_fail (user != NULL, FALSE);
171  g_return_val_if_fail (password != NULL, FALSE);
172 
173  *password = NULL;
174 
175 #ifdef HAVE_LIBSECRET
176  libsecret_password = secret_password_lookup_sync (SECRET_SCHEMA_GNUCASH, NULL, &error,
177  "protocol", access_method,
178  "server", server,
179  "port", port,
180  "user", *user,
181  NULL);
182 
183  if (libsecret_password == NULL) {
184  if (error != NULL) {
185  PWARN ("libsecret access failed: %s.", error->message);
186  g_error_free(error);
187  }
188  } else {
189  password_found = TRUE;
190  *password = g_strdup (libsecret_password);
191  secret_password_free (libsecret_password);
192  }
193 #endif /* HAVE_LIBSECRET */
194 
195 #if HAVE_GNOME_KEYRING
196  if (password_found == FALSE) {
197  gkr_result = gnome_keyring_find_network_password_sync
198  ( *user, NULL, server, service,
199  access_method, NULL, port, &found_list );
200 
201  if (gkr_result == GNOME_KEYRING_RESULT_OK)
202  {
203  found = (GnomeKeyringNetworkPasswordData *) found_list->data;
204  if (found->password)
205  *password = g_strdup(found->password);
206  password_found = TRUE;
207  }
208  else
209  PWARN ("Gnome-keyring access failed: %s.",
210  gnome_keyring_result_to_message(gkr_result));
211 
212  gnome_keyring_network_password_list_free(found_list);
213  }
214 #endif /* HAVE_GNOME_KEYRING */
215 
216 #if defined(HAVE_LIBSECRET) && defined(HAVE_GNOME_KEYRING)
217  /* If we were not able to retrieve the password with libsecret and the new
218  * schema and libgnome-keyring was successful to retrieve the password using
219  * the old schema, we immediatly store it in the new schema.
220  */
221  if (libsecret_password == NULL && password_found == TRUE) {
222  gnc_keyring_set_password(access_method, server, port, service, *user, *password);
223  }
224 #endif /* HAVE_LIBSECRET && HAVE_GNOME_KEYRING */
225 
226 #ifdef HAVE_OSX_KEYCHAIN
227  /* mysql and postgres aren't valid protocols on Mac OS X.
228  * So we use the security domain parameter to allow us to
229  * distinguish between these two.
230  */
231  if (*user != NULL)
232  {
233  status = SecKeychainFindInternetPassword( NULL,
234  strlen(server), server,
235  strlen(access_method), access_method,
236  strlen(*user), *user,
237  strlen(service), service,
238  port,
239  kSecProtocolTypeAny,
240  kSecAuthenticationTypeDefault,
241  &password_length, &password_data,
242  NULL);
243 
244  if ( status == noErr )
245  {
246  *password = g_strndup(password_data, password_length);
247  password_found = TRUE;
248  SecKeychainItemFreeContent(NULL, password_data);
249  }
250  else
251  {
252  CFStringRef osx_resultstring = SecCopyErrorMessageString( status, NULL );
253  const gchar *resultstring = CFStringGetCStringPtr(osx_resultstring,
254  GetApplicationTextEncoding());
255  PWARN ( "OS X keychain error: %s", resultstring );
256  CFRelease ( osx_resultstring );
257  }
258  }
259 #endif /* HAVE_OSX_KEYCHAIN */
260 
261  if ( !password_found )
262  {
263  /* If we got here, either no proper password store is
264  * available on this system, or we couldn't retrieve
265  * a password from it. In both cases, just ask the user
266  * to enter one
267  */
268  gchar *db_path, *heading;
269 
270  if ( port == 0 )
271  db_path = g_strdup_printf ( "%s://%s/%s", access_method, server, service );
272  else
273  db_path = g_strdup_printf ( "%s://%s:%d/%s", access_method, server, port, service );
274  heading = g_strdup_printf ( /* Translators: %s is a path to a database or any other url,
275  like mysql://[email protected]/somedb, http://www.somequotes.com/thequotes */
276  _("Enter a user name and password to connect to: %s"),
277  db_path );
278 
279  password_found = gnc_get_username_password ( parent, heading,
280  *user, NULL,
281  user, password );
282  g_free ( db_path );
283  g_free ( heading );
284 
285  if ( password_found )
286  {
287  /* User entered new user/password information
288  * Let's try to add it to a password store.
289  */
290  gchar *newuser = g_strdup( *user );
291  gchar *newpassword = g_strdup( *password );
292  gnc_keyring_set_password ( access_method,
293  server,
294  port,
295  service,
296  newuser,
297  newpassword );
298  g_free ( newuser );
299  g_free ( newpassword );
300  }
301  }
302 
303  return password_found;
304 }
#define PWARN(format, args...)
Definition: qoflog.h:243
void gnc_keyring_set_password(const gchar *access_method, const gchar *server, guint32 port, const gchar *service, const gchar *user, const gchar *password)
Definition: gnc-keyring.c:67
void gnc_keyring_set_password ( const gchar *  access_method,
const gchar *  server,
guint32  port,
const gchar *  service,
const gchar *  user,
const gchar *  password 
)

Attempt to store a password in some trusted keystore. At this point that can be Gnome's keyring or Mac OS X' keychain. If no such keystore is available, this function does nothing.

All the parameters passed (except for the password) will be used to create a unique key, so the password can later be retrieved again with the same parameters.

Parameters
access_methodService type the user attempts to access. Can things like 'mysql', 'postgres' and so on.
serverServer the user wishes to connect to.
portPort the service listens on. If set to 0, it will be ignored in the search for a password.
serviceThe service the user wishes to access on the server. This can be a database name or a path.
userThe username to access the service.
passwordThe password to access the service.

Definition at line 67 of file gnc-keyring.c.

73 {
74 #ifdef HAVE_LIBSECRET
75  GError* error = NULL;
76  gchar* label = NULL;
77 
78  label = g_strdup_printf("GnuCash password for %s://%s@%s", access_method, user, server);
79 
80  secret_password_store_sync (SECRET_SCHEMA_GNUCASH, SECRET_COLLECTION_DEFAULT,
81  label, password, NULL, &error,
82  "protocol", access_method,
83  "server", server,
84  "port", port,
85  "user", user,
86  NULL);
87 
88  g_free(label);
89 
90  if (error != NULL)
91  {
92  PWARN ("libsecret error: %s", error->message);
93  PWARN ("The user will be prompted for a password again next time.");
94  g_error_free(error);
95  }
96 #elif HAVE_GNOME_KEYRING
97  GnomeKeyringResult gkr_result;
98  guint32 item_id = 0;
99 
100  gkr_result = gnome_keyring_set_network_password_sync
101  (NULL, user, NULL, server, service,
102  access_method, NULL, port, password, &item_id);
103 
104  if (gkr_result != GNOME_KEYRING_RESULT_OK)
105  {
106  PWARN ("Gnome-keyring error: %s",
107  gnome_keyring_result_to_message(gkr_result));
108  PWARN ("The user will be prompted for a password again next time.");
109  }
110 #endif /* HAVE_GNOME_KEYRING */
111 #ifdef HAVE_OSX_KEYCHAIN
112  OSStatus status;
113  SecKeychainItemRef *itemRef = NULL;
114 
115  /* mysql and postgres aren't valid protocols on Mac OS X.
116  * So we use the security domain parameter to allow us to
117  * distinguish between these two.
118  */
119  // FIXME I'm not sure this works if a password was already in the keychain
120  // I may have to do a lookup first and if it exists, run some update
121  // update function instead
122  status = SecKeychainAddInternetPassword ( NULL, /* keychain */
123  strlen(server), server, /* servername */
124  strlen(access_method), access_method, /* securitydomain */
125  strlen(user), user, /* acountname */
126  strlen(service), service, /* path */
127  port, /* port */
128  kSecProtocolTypeAny, /* protocol */
129  kSecAuthenticationTypeDefault, /* auth type */
130  strlen(password), password, /* passworddata */
131  itemRef );
132 
133  if ( status != noErr )
134  {
135  CFStringRef osx_resultstring = SecCopyErrorMessageString( status, NULL );
136  const gchar *resultstring = CFStringGetCStringPtr(osx_resultstring,
137  GetApplicationTextEncoding());
138  PWARN ( "OS X keychain error: %s", resultstring );
139  PWARN ( "The user will be prompted for a password again next time." );
140  CFRelease ( osx_resultstring );
141  }
142 #endif /* HAVE_OSX_KEYCHAIN */
143 }
#define PWARN(format, args...)
Definition: qoflog.h:243