commit c25dc24828315b0f80dc3e94cfe3820a04f2dd32
Author: Oswald Buddenhagen <[email protected]>
Date: Wed Nov 27 17:13:44 2019 +0100
add option to get password from macOS Keychain
this is better than using PassCmd, as it allows the keychain manager to
identify the calling process and therefore use a selective whitelist.
unlike in the now removed example, we use an "internet password" for the
imap protocol, rather than a "generic password" - this seems more
appropriate.
based on a patch by
CCMAIL: Oliver Runge <[email protected]>
configure.ac | 34 +++++++++++++++++++++++++++++++++-
src/Makefile.am | 2 +-
src/drv_imap.c | 43 +++++++++++++++++++++++++++++++++++++++++++
src/mbsync.1 | 22 ++++++++++++++++++++++
src/mbsyncrc.sample | 5 -----
5 files changed, 99 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 811db2c..50e5ddb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,9 @@
AC_INIT([isync], [1.4.0])
AC_CONFIG_HEADERS([autodefs.h])
-AM_INIT_AUTOMAKE
+AC_CANONICAL_TARGET
+
+AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE
AC_PROG_CC_C99
@@ -198,6 +200,29 @@ fi
AM_CONDITIONAL(with_mdconvert, test "x$ac_cv_berkdb4" = xyes)
+case $target_os in
+darwin*)
+ darwin=yes
+;;
+*)
+ darwin=no
+;;
+esac
+
+AC_ARG_WITH(
+ macos-keychain,
+ [AS_HELP_STRING([--with-macos-keychain], [Support macOS keychain])],
+ [have_macos_keychain=$withval],
+ [have_macos_keychain=$darwin])
+if test "x$have_macos_keychain" != xno; then
+ if test $darwin = no; then
+ AC_MSG_ERROR([Cannot use macOS Keychain outside macOS.])
+ fi
+ have_macos_keychain=yes
+ AC_DEFINE(HAVE_MACOS_KEYCHAIN, 1, [Define to 1 if you have the macOS
Keychain Services API.])
+ AC_SUBST(KEYCHAIN_LIBS, ["-Wl,-framework,Security"])
+fi
+
AC_CONFIG_FILES([Makefile src/Makefile isync.spec])
AC_OUTPUT
@@ -222,4 +247,11 @@ if test "x$ac_cv_berkdb4" = xyes; then
else
AC_MSG_RESULT([Not using Berkeley DB])
fi
+if test $darwin = yes; then
+ if test "x$have_macos_keychain" = xyes; then
+ AC_MSG_RESULT([Using macOS Keychain])
+ else
+ AC_MSG_RESULT([Not using macOS Keychain])
+ fi
+fi
AC_MSG_RESULT()
diff --git a/src/Makefile.am b/src/Makefile.am
index 63c4e22..76dff34 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c
drv_maildir.c drv_proxy.c
-mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS)
+mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS)
$(KEYCHAIN_LIBS)
noinst_HEADERS = common.h config.h driver.h sync.h socket.h
drv_proxy.$(OBJEXT): drv_proxy.inc
diff --git a/src/drv_imap.c b/src/drv_imap.c
index 02da99a..7474969 100644
--- a/src/drv_imap.c
+++ b/src/drv_imap.c
@@ -41,6 +41,10 @@
# include <sasl/saslutil.h>
#endif
+#ifdef HAVE_MACOS_KEYCHAIN
+# include <Security/Security.h>
+#endif
+
#ifdef HAVE_LIBSSL
enum { SSL_None, SSL_STARTTLS, SSL_IMAPS };
#endif
@@ -58,6 +62,9 @@ typedef struct imap_server_conf {
string_list_t *auth_mechs;
#ifdef HAVE_LIBSSL
char ssl_type;
+#endif
+#ifdef HAVE_MACOS_KEYCHAIN
+ char use_keychain;
#endif
char failed;
} imap_server_conf_t;
@@ -1996,6 +2003,31 @@ ensure_password( imap_server_conf_t *srvc )
if (!srvc->pass) {
if (srvc->pass_cmd) {
srvc->pass = cred_from_cmd( "PassCmd", srvc->pass_cmd,
srvc->name );
+#ifdef HAVE_MACOS_KEYCHAIN
+ } else if (srvc->use_keychain) {
+ void *password_data;
+ UInt32 password_length;
+ OSStatus ret = SecKeychainFindInternetPassword(
+ NULL, // keychainOrArray
+ strlen( srvc->sconf.host ),
srvc->sconf.host,
+ 0, NULL, // securityDomain
+ strlen( srvc->user ), srvc->user,
+ 0, NULL, // path
+ 0, // port - we could use it, but it
seems pointless
+ kSecProtocolTypeIMAP,
+ kSecAuthenticationTypeDefault,
+ &password_length, &password_data,
+ NULL ); // itemRef
+ if (ret != errSecSuccess) {
+ CFStringRef errmsg = SecCopyErrorMessageString(
ret, NULL );
+ error( "Looking up Keychain failed: %s\n",
+ CFStringGetCStringPtr( errmsg,
kCFStringEncodingUTF8 ) );
+ CFRelease( errmsg );
+ return NULL;
+ }
+ srvc->pass = nfstrndup( password_data, password_length
);
+ SecKeychainItemFreeContent( NULL, password_data );
+#endif /* HAVE_MACOS_KEYCHAIN */
} else {
flushn();
char prompt[80];
@@ -3300,6 +3332,10 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep
)
server->pass = nfstrdup( cfg->val );
else if (!strcasecmp( "PassCmd", cfg->cmd ))
server->pass_cmd = nfstrdup( cfg->val );
+#ifdef HAVE_MACOS_KEYCHAIN
+ else if (!strcasecmp( "UseKeychain", cfg->cmd ))
+ server->use_keychain = parse_bool( cfg );
+#endif
else if (!strcasecmp( "Port", cfg->cmd )) {
int port = parse_int( cfg );
if ((unsigned)port > 0xffff) {
@@ -3469,6 +3505,13 @@ imap_parse_store( conffile_t *cfg, store_conf_t **storep
)
cfg->err = 1;
return 1;
}
+#ifdef HAVE_MACOS_KEYCHAIN
+ if (server->use_keychain && (server->pass || server->pass_cmd))
{
+ error( "%s '%s' has UseKeychain enabled despite
specifying Pass/PassCmd\n", type, name );
+ cfg->err = 1;
+ return 1;
+ }
+#endif
#ifdef HAVE_LIBSSL
if ((use_tlsv1 & use_tlsv11 & use_tlsv12 & use_tlsv13) != -1 ||
use_imaps >= 0 || require_ssl >= 0) {
if (server->ssl_type >= 0 || server->sconf.ssl_versions
>= 0) {
diff --git a/src/mbsync.1 b/src/mbsync.1
index 4f6dfae..1b02471 100644
--- a/src/mbsync.1
+++ b/src/mbsync.1
@@ -341,6 +341,28 @@ Prepend \fB+\fR to the command to indicate that it
produces TTY output
messier output.
.
.TP
+\fBUseKeychain\fR \fByes\fR|\fBno\fR
+Whether to use the macOS Keychain to obtain the password.
+(Default: \fBno\fR)
+.IP
+The neccessary keychain item can be created this way:
+.RS
+.IP
+.nh
+.B security add-internet-password \-r imap \-s
+.I Host
+.B \-a
+.I User
+.B \-w
+.I password
+[
+.B \-T
+.I /path/to/mbsync
+]
+.hy
+.RE
+.
+.TP
\fBTunnel\fR \fIcommand\fR
Specify a command to run to establish a connection rather than opening a TCP
socket. This allows you to run an IMAP session over an SSH tunnel, for
diff --git a/src/mbsyncrc.sample b/src/mbsyncrc.sample
index abf74e5..a9d9b13 100644
--- a/src/mbsyncrc.sample
+++ b/src/mbsyncrc.sample
@@ -21,11 +21,6 @@ Pass xxxxxxxx
#PassCmd "gpg --quiet --for-your-eyes-only --decrypt $HOME/imappassword.gpg"
# Fetch password from pwmd (http://pwmd.sourceforge.net/):
#PassCmd "echo -ne 'GET myIsp\\tpassword' | pwmc datafile"
-# On macOS, run "KeyChain Access" -- File->New Password Item. Fill out form
using
-# "Keychain Item Name" http://IMAPSERVER (note: the "http://" is a hack)
-# "Account Name" USERNAME
-# "Password" PASSWORD
-#PassCmd "/usr/bin/security find-internet-password -w -a USERNAME -s
IMAPSERVER ~/Library/Keychains/login.keychain"
Channel work
Master :work:
_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel