From 5b892d8374e27edfbf9d2902cd7c26d0b54c67bd Mon Sep 17 00:00:00 2001
From: Jay Soffian <jaysoffian@gmail.com>
Date: Tue, 5 Feb 2008 03:36:48 -0500
Subject: [PATCH] Support for Mac OS X keychain
The Mac OS X keychain provides a more secure mechanism for storing passwords
than a plaintext file such as .netrc or .msmtprc. The attached patch allows
msmtp to retrieve its account passwords from the keychain.
To make use of the functionality, an OS X user creates a keychain item with
tje Keychain Access GUI application. The "account name" is simply the value of
the msmtp "user" argument. However, the "keychain item name" is
"smtp://<hostname>" where "<hostname>" matches the msmtp host argument. Using
"smtp://" is needed so that the item is created of kind "Internet password."
For example, selecting "File -> Get Info" on a keychain item that corresponds
to "host smtp.freemail.example" and "user joe.smith" will show:
Name: smtp.freemail.example
Kind: Internet password
Account: joe.smith
Where: smtp://smtp.freemail.example
Signed-off-by: Jay Soffian <jaysoffian@gmail.com>
---
configure.ac | 16 ++++++++++++++++
src/msmtp.c | 31 +++++++++++++++++++++++++++++--
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index eeaa734..97a202d 100644
a
|
b
|
if test "$libidn" != "no"; then |
179 | 179 | fi |
180 | 180 | fi |
181 | 181 | |
| 182 | dnl MacOS X Keychain Services (Security Framework) |
| 183 | AC_CACHE_CHECK([for SecKeychainGetVersion], |
| 184 | ac_cv_func_SecKeychainGetVersion, |
| 185 | [ac_save_LIBS="$LIBS" |
| 186 | LIBS="$LIBS -Wl,-framework -Wl,Security" |
| 187 | AC_TRY_LINK([#include <Security/Security.h>], |
| 188 | [SecKeychainGetVersion(NULL);], |
| 189 | [ac_cv_func_SecKeychainGetVersion=yes], |
| 190 | [ac_cv_func_SecKeychainGetVersion=no]) |
| 191 | LIBS="$ac_save_LIBS"]) |
| 192 | if test $ac_cv_func_SecKeychainGetVersion = yes; then |
| 193 | AC_DEFINE([HAVE_KEYCHAIN], 1, |
| 194 | [Define to 1 if you have the MacOS X Keychain Services API.]) |
| 195 | LIBS="$LIBS -Wl,-framework -Wl,Security" |
| 196 | fi |
| 197 | |
182 | 198 | dnl Global #defines for all source files |
183 | 199 | AH_VERBATIM([UNUSED], |
184 | 200 | [/* Let gcc know about unused variables to suppress warnings. |
diff --git a/src/msmtp.c b/src/msmtp.c
index fef0f5c..f0e30b7 100644
a
|
b
|
extern int optind; |
56 | 56 | #include <netdb.h> |
57 | 57 | #include <arpa/inet.h> |
58 | 58 | #endif |
59 | | |
| 59 | #ifdef HAVE_KEYCHAIN |
| 60 | #include <Security/Security.h> |
| 61 | #endif |
60 | 62 | #include "getpass.h" |
61 | 63 | #include "gettext.h" |
62 | 64 | #include "xalloc.h" |
… |
… |
char *msmtp_password_callback(const char *hostname, const char *user) |
284 | 286 | char *prompt; |
285 | 287 | char *gpw; |
286 | 288 | char *password = NULL; |
| 289 | #ifdef HAVE_KEYCHAIN |
| 290 | void *passwordData; |
| 291 | UInt32 passwordLength; |
| 292 | OSStatus status; |
| 293 | #endif |
287 | 294 | |
288 | 295 | homedir = get_homedir(); |
289 | 296 | netrc_filename = get_filename(homedir, NETRCFILE); |
… |
… |
char *msmtp_password_callback(const char *hostname, const char *user) |
297 | 304 | free_netrc_entry_list(netrc_hostlist); |
298 | 305 | } |
299 | 306 | free(netrc_filename); |
300 | | |
| 307 | |
| 308 | #ifdef HAVE_KEYCHAIN |
| 309 | if (SecKeychainFindInternetPassword( |
| 310 | NULL, |
| 311 | strlen(hostname), hostname, |
| 312 | 0, NULL, |
| 313 | strlen(user), user, |
| 314 | 0, (char *)NULL, |
| 315 | 0, |
| 316 | kSecProtocolTypeSMTP, |
| 317 | kSecAuthenticationTypeDefault, |
| 318 | &passwordLength, &passwordData, |
| 319 | NULL) == noErr) |
| 320 | { |
| 321 | password = xmalloc((passwordLength + 1) * sizeof(char)); |
| 322 | strncpy(password, passwordData, (size_t)passwordLength); |
| 323 | password[passwordLength] = '\0'; |
| 324 | SecKeychainItemFreeContent(NULL, passwordData); |
| 325 | } |
| 326 | #endif /* HAVE_KEYCHAIN */ |
| 327 | |
301 | 328 | if (!password) |
302 | 329 | { |
303 | 330 | prompt = xasprintf(_("password for %s at %s: "), user, hostname); |