From: Peter G. <pg...@gm...> - 2016-09-11 20:00:48
|
- Attempt to retrieve credentials from the Mac OS X Keychain Services framework based on the account name, server name, and protocol of the configured query. This allows us to avoid storing passwords in the the .fetchmailrc file and to take advantage of Keychain's ACL features to ensure that only fetchmail and a few other select applications have access to these credentials. - Add a new configure --with-keychain option gating this feature - Update fetchmail.man with description of OS X Keychain item format recognizable by fetchmail and a recipe for adding a conforming item --- configure.ac | 10 +++++++++ fetchmail.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fetchmail.man | 19 ++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/configure.ac b/configure.ac index 5efd8d1..78d3cf7 100644 --- a/configure.ac +++ b/configure.ac @@ -527,6 +527,16 @@ if test "$fm_cv_getaddrinfo" = yes ; then fi fi +# Optionally support credential retrieval from OS X Keychain Services +AC_ARG_WITH(keychain, + [AS_HELP_STRING([--with-keychain], + [use the Mac OS X keychain for credential storage])], + [], + [with_keychain=no]) +AS_IF([test "x$with_keychain" = xyes], + AC_DEFINE([HAVE_KEYCHAIN], [1], [Enable OS X Keychain integration]) + [LIBS="$LIBS -Wl,-framework -Wl,Security -Wl,-framework -Wl,CoreFoundation"]) + # This version of the Kerberos 4 and 5 options addresses the follwing issues: # # * Build correctly under Heimdal kerberos if it is compiled with db2 and diff --git a/fetchmail.c b/fetchmail.c index ae30f90..9535075 100644 --- a/fetchmail.c +++ b/fetchmail.c @@ -37,6 +37,10 @@ #include <langinfo.h> #endif +#ifdef HAVE_KEYCHAIN +#include <Security/Security.h> +#endif + #include "fetchmail.h" #include "socket.h" #include "tunable.h" @@ -284,6 +288,9 @@ int main(int argc, char **argv) #ifndef HAVE_RES_SEARCH "-DNS" #endif +#ifdef HAVE_KEYCHAIN + "+KEYCHAIN" +#endif ".\n"; printf(GT_("This is fetchmail release %s"), VERSION); fputs(features, stdout); @@ -560,6 +567,69 @@ int main(int argc, char **argv) } } +#ifdef HAVE_KEYCHAIN + /* look in the OS X keychain for remaining un-set passwords */ + for (ctl = querylist; ctl; ctl = ctl->next) + { + if (!ctl->active || NO_PASSWORD(ctl) || ctl->password + || (implicitmode && ctl->server.skip)) + { + continue; + } + + const char *host = (ctl->server.via) ? + ctl->server.via : + ctl->server.pollname; + const SecProtocolType protocol_type = + (ctl->server.protocol == P_IMAP) ? kSecProtocolTypeIMAP : + (ctl->server.protocol == P_POP2) ? kSecProtocolTypePOP3 : + (ctl->server.protocol == P_POP3) ? kSecProtocolTypePOP3 : + (ctl->server.protocol == P_APOP) ? kSecProtocolTypePOP3 : + (ctl->server.protocol == P_RPOP) ? kSecProtocolTypePOP3 : + kSecProtocolTypeAny; + + uint32_t password_len; + void* password_bytes; + OSStatus oss = SecKeychainFindInternetPassword( + NULL, + strlen(host), host, /* server */ + 0, NULL, /* security domain */ + strlen(ctl->remotename), ctl->remotename, /* account name */ + 0, NULL, /* path */ + 0, /* port */ + protocol_type, + kSecAuthenticationTypeDefault, + &password_len, &password_bytes, /* password */ + NULL /* SecKeychainItemRef */); + + if (oss != errSecSuccess && outlevel >= O_VERBOSE) + { + char errstr[512]; + CFStringRef cferrstr = SecCopyErrorMessageString(oss, NULL); + Boolean ok = CFStringGetCString( + cferrstr, + errstr, + sizeof(errstr), + kCFStringEncodingUTF8); + if (!ok) + { + strcpy(errstr, "Unknown; CFStringGetCString() failed"); + } + + report(stderr, + "SecKeychainFindInternetPassword: %s (%d)\n", + errstr, + oss); + continue; + } + + ctl->password = (char*) xmalloc(password_len + 1); + memmove(ctl->password, password_bytes, password_len); + ctl->password[password_len] = '\0'; + (void) SecKeychainItemFreeContent(NULL, password_bytes); + } +#endif + /* pick up interactively any passwords we need but don't have */ for (ctl = querylist; ctl; ctl = ctl->next) { diff --git a/fetchmail.man b/fetchmail.man index 792ada2..b60238a 100644 --- a/fetchmail.man +++ b/fetchmail.man @@ -1200,6 +1200,25 @@ password en clair) whenever the server returns AUTH=NTLM in its capability response. Specify a user option value that looks like \&'user@domain': the part to the left of the @ will be passed as the username and the part to the right as the NTLM domain. +.PP +If your \fBfetchmail\fP was built with OS X Keychain support, the current +user's keychain will be searched for credentials. \fBfetchmail\fP looks for an +entry of type "Internet password" with the "Account" field matching the +username used for authentication, and the "Where" field a URI matching the +protocol and server name (e.g. "imap://imap.gmail.com"). It does not appear +possible to create an "Internet password" entry using the \fIKeychain Access\fP +GUI tool; one must use the \fIsecurity(1)\fP tool. Below is an example of using +this tool to set up an properly-configured entry for authenticating the user +"pgriess" to Google's IMAP server: + + $ security add-internet-password \\ + -a pgriess \\ + -r imap \\ + -s imap.gmail.com \\ + -w <password> + +Use "-r pop3" for all POP-related \fBfetchmail\fP protocols including POP2, +APOP, etc. .SS Secure Socket Layers (SSL) and Transport Layer Security (TLS) .PP -- 2.8.0-rc2 |