Last active
March 21, 2018 00:20
-
-
Save leonklingele/afdb457f1b378b42bdbfdbc5fd59f55c to your computer and use it in GitHub Desktop.
Homebrew openssh-7.5p1 patches
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 32a85e260f85fc820fd026637ad38e2230d2887f Mon Sep 17 00:00:00 2001 | |
From: Leon Klingele <[email protected]> | |
Date: Tue, 21 Mar 2017 22:37:56 +0100 | |
Subject: [PATCH 1/3] 0001-apple-keychain-integration-other-changes.patch | |
--- | |
Makefile.in | 18 +- | |
audit-bsm.c | 7 +- | |
auth-pam.c | 5 +- | |
auth.c | 2 +- | |
authfd.c | 23 ++ | |
authfd.h | 6 + | |
config.h.in | 12 + | |
configure.ac | 30 +++ | |
groupaccess.c | 57 ++++- | |
groupaccess.h | 2 +- | |
keychain.c | 694 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
keychain.h | 45 ++++ | |
readconf.c | 19 ++ | |
readconf.h | 4 + | |
scp.1 | 4 +- | |
scp.c | 148 +++++++++++++ | |
servconf.c | 4 +- | |
session.c | 4 + | |
ssh-add.0 | 9 +- | |
ssh-add.1 | 9 +- | |
ssh-add.c | 56 ++++- | |
ssh-agent.c | 141 ++++++++++++ | |
ssh-keysign.8 | 3 + | |
sshconnect1.c | 5 + | |
sshconnect2.c | 5 + | |
sshd.0 | 3 +- | |
sshd.8 | 3 - | |
sshd.c | 12 +- | |
sshd_config | 12 +- | |
sshd_config.0 | 4 +- | |
sshd_config.5 | 4 +- | |
31 files changed, 1299 insertions(+), 51 deletions(-) | |
create mode 100644 keychain.c | |
create mode 100644 keychain.h | |
diff --git a/Makefile.in b/Makefile.in | |
index 5870e9e..48a13db 100644 | |
--- a/Makefile.in | |
+++ b/Makefile.in | |
@@ -59,6 +59,7 @@ SED=@SED@ | |
ENT=@ENT@ | |
XAUTH_PATH=@XAUTH_PATH@ | |
LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ | |
+KEYCHAIN_LDFLAGS=@KEYCHAIN_LDFLAGS@ | |
EXEEXT=@EXEEXT@ | |
MANFMT=@MANFMT@ | |
@@ -112,6 +113,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ | |
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \ | |
sandbox-solaris.o | |
+KEYCHAINOBJS=keychain.o | |
+ | |
MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out | |
MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 | |
MANTYPE = @MANTYPE@ | |
@@ -147,6 +150,7 @@ all: $(CONFIGFILES) $(MANPAGES) $(TARGETS) | |
$(LIBSSH_OBJS): Makefile.in config.h | |
$(SSHOBJS): Makefile.in config.h | |
$(SSHDOBJS): Makefile.in config.h | |
+$(KEYCHAINOBJS): Makefile.in config.h | |
.c.o: | |
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ | |
@@ -160,8 +164,8 @@ libssh.a: $(LIBSSH_OBJS) | |
$(AR) rv $@ $(LIBSSH_OBJS) | |
$(RANLIB) $@ | |
-ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) | |
- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) | |
+ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) $(KEYCHAINOBJS) | |
+ $(LD) -o $@ $(SSHOBJS) $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) | |
sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) | |
$(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) | |
@@ -169,11 +173,11 @@ sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) | |
scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o | |
$(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | |
-ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o | |
- $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | |
+ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o $(KEYCHAINOBJS) | |
+ $(LD) -o $@ ssh-add.o $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | |
-ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o | |
- $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | |
+ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o $(KEYCHAINOBJS) | |
+ $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | |
ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o | |
$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | |
@@ -324,7 +328,7 @@ install-files: | |
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) | |
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) | |
$(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT) | |
- $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) | |
+ $(INSTALL) -m 0711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) | |
$(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) | |
$(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) | |
$(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) | |
diff --git a/audit-bsm.c b/audit-bsm.c | |
index f8e0bea..b91a775 100644 | |
--- a/audit-bsm.c | |
+++ b/audit-bsm.c | |
@@ -261,7 +261,12 @@ bsm_audit_record(int typ, char *string, au_event_t event_no) | |
pid_t pid = getpid(); | |
AuditInfoTermID tid = ssh_bsm_tid; | |
- if (the_authctxt != NULL && the_authctxt->valid) { | |
+ if (the_authctxt == NULL) { | |
+ error("BSM audit: audit record internal error (NULL ctxt)"); | |
+ abort(); | |
+ } | |
+ | |
+ if (the_authctxt->valid) { | |
uid = the_authctxt->pw->pw_uid; | |
gid = the_authctxt->pw->pw_gid; | |
} | |
diff --git a/auth-pam.c b/auth-pam.c | |
index bc8e5e0..103b6cb 100644 | |
--- a/auth-pam.c | |
+++ b/auth-pam.c | |
@@ -798,10 +798,11 @@ sshpam_query(void *ctx, char **name, char **info, | |
free(msg); | |
return (0); | |
} | |
- error("PAM: %s for %s%.100s from %.100s", msg, | |
+ error("PAM: %s for %s%.100s from %.100s via %s", msg, | |
sshpam_authctxt->valid ? "" : "illegal user ", | |
sshpam_authctxt->user, | |
- auth_get_canonical_hostname(ssh, options.use_dns)); | |
+ auth_get_canonical_hostname(ssh, options.use_dns), | |
+ get_local_ipaddr(ssh_packet_get_connection_in(ssh))); | |
/* FALLTHROUGH */ | |
default: | |
*num = 0; | |
diff --git a/auth.c b/auth.c | |
index 6ee6116..95bb13a 100644 | |
--- a/auth.c | |
+++ b/auth.c | |
@@ -226,7 +226,7 @@ allowed_user(struct passwd * pw) | |
} | |
if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { | |
/* Get the user's group access list (primary and supplementary) */ | |
- if (ga_init(pw->pw_name, pw->pw_gid) == 0) { | |
+ if (ga_init(pw) == 0) { | |
logit("User %.100s from %.100s not allowed because " | |
"not in any group", pw->pw_name, hostname); | |
return 0; | |
diff --git a/authfd.c b/authfd.c | |
index a634bcb..fe018c1 100644 | |
--- a/authfd.c | |
+++ b/authfd.c | |
@@ -165,6 +165,29 @@ ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply) | |
} | |
/* | |
+ * Adds identities using passphrases stored in the keychain. This call is not | |
+ * meant to be used by normal applications. | |
+ */ | |
+ | |
+int | |
+ssh_add_from_keychain(int agent_fd) | |
+{ | |
+ Buffer msg; | |
+ int type; | |
+ | |
+ buffer_init(&msg); | |
+ buffer_put_char(&msg, SSH_AGENTC_ADD_FROM_KEYCHAIN); | |
+ | |
+ if (ssh_request_reply(agent_fd, &msg, &msg) == 0) { | |
+ buffer_free(&msg); | |
+ return 0; | |
+ } | |
+ type = buffer_get_char(&msg); | |
+ buffer_free(&msg); | |
+ return decode_reply(type); | |
+} | |
+ | |
+/* | |
* Closes the agent socket if it should be closed (depends on how it was | |
* obtained). The argument must have been returned by | |
* ssh_get_authentication_socket(). | |
diff --git a/authfd.h b/authfd.h | |
index 4b417e3..33ce33e 100644 | |
--- a/authfd.h | |
+++ b/authfd.h | |
@@ -43,6 +43,9 @@ int ssh_agent_sign(int sock, struct sshkey *key, | |
u_char **sigp, size_t *lenp, | |
const u_char *data, size_t datalen, const char *alg, u_int compat); | |
+int | |
+ssh_add_from_keychain(int agent_fd); | |
+ | |
/* Messages for the authentication agent connection. */ | |
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 | |
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 | |
@@ -76,6 +79,9 @@ int ssh_agent_sign(int sock, struct sshkey *key, | |
#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 | |
#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 | |
+/* keychain */ | |
+#define SSH_AGENTC_ADD_FROM_KEYCHAIN 27 | |
+ | |
#define SSH_AGENT_CONSTRAIN_LIFETIME 1 | |
#define SSH_AGENT_CONSTRAIN_CONFIRM 2 | |
diff --git a/config.h.in b/config.h.in | |
index b65420e..1ec0ab8 100644 | |
--- a/config.h.in | |
+++ b/config.h.in | |
@@ -78,6 +78,18 @@ | |
/* strnvis detected broken */ | |
#undef BROKEN_STRNVIS | |
+/* platform uses an in-memory credentials cache */ | |
+#undef USE_CCAPI | |
+ | |
+/* platform has a Security Authorization Session API */ | |
+#undef USE_SECURITY_SESSION_API | |
+ | |
+/* Define to 1 if you have the `copyfile' function. */ | |
+#undef HAVE_COPYFILE | |
+ | |
+/* Define to 1 if you have the <copyfile.h> header file. */ | |
+#undef HAVE_COPYFILE_H | |
+ | |
/* tcgetattr with ICANON may hang */ | |
#undef BROKEN_TCGETATTR_ICANON | |
diff --git a/configure.ac b/configure.ac | |
index c2878e3..c47412d 100644 | |
--- a/configure.ac | |
+++ b/configure.ac | |
@@ -5029,10 +5029,40 @@ AC_CHECK_MEMBER([struct utmp.ut_line], [], [ | |
#endif | |
]) | |
+dnl Keychain support | |
+AC_ARG_WITH(keychain, | |
+ [ --with-keychain=apple Use Mac OS X Keychain], | |
+ [ | |
+ case "$withval" in | |
+ apple|no) | |
+ KEYCHAIN=$withval | |
+ ;; | |
+ *) | |
+ AC_MSG_ERROR(invalid keychain type: $withval) | |
+ ;; | |
+ esac | |
+ ] | |
+) | |
+if test ! -z "$KEYCHAIN" -a "$KEYCHAIN" != "no"; then | |
+ case "$KEYCHAIN" in | |
+ apple) | |
+ AC_CHECK_HEADERS(Security/Security.h, [ | |
+ CPPFLAGS="$CPPFLAGS -D__APPLE_KEYCHAIN__" | |
+ KEYCHAIN_LDFLAGS="-framework Security -framework CoreFoundation" | |
+ AC_SUBST(KEYCHAIN_LDFLAGS) | |
+ ], | |
+ AC_MSG_WARN([Security framework not found. Disabling Mac OS X Keychain support.])) | |
+ ;; | |
+ esac | |
+fi | |
+ | |
dnl Adding -Werror to CFLAGS early prevents configure tests from running. | |
dnl Add now. | |
CFLAGS="$CFLAGS $werror_flags" | |
+AC_CHECK_FUNCS(copyfile) | |
+AC_CHECK_HEADERS(copyfile.h) | |
+ | |
if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then | |
TEST_SSH_IPV6=no | |
else | |
diff --git a/groupaccess.c b/groupaccess.c | |
index 2518c84..f5e8c36 100644 | |
--- a/groupaccess.c | |
+++ b/groupaccess.c | |
@@ -34,38 +34,67 @@ | |
#include <string.h> | |
#include <limits.h> | |
+#ifdef __APPLE_MEMBERSHIP__ | |
+#include <membership.h> | |
+#endif | |
+ | |
#include "xmalloc.h" | |
#include "groupaccess.h" | |
#include "match.h" | |
#include "log.h" | |
+#ifdef __APPLE_MEMBERSHIP__ | |
+// SPI for 5235093 | |
+int32_t getgrouplist_2(const char *, gid_t, gid_t **); | |
+int32_t getgroupcount(const char *, gid_t); | |
+#endif | |
+ | |
static int ngroups; | |
static char **groups_byname; | |
+#ifdef __APPLE_MEMBERSHIP__ | |
+uuid_t u_uuid; | |
+#endif | |
/* | |
* Initialize group access list for user with primary (base) and | |
* supplementary groups. Return the number of groups in the list. | |
*/ | |
int | |
-ga_init(const char *user, gid_t base) | |
+ga_init(struct passwd *pw) | |
{ | |
- gid_t *groups_bygid; | |
+ gid_t *groups_bygid = NULL; | |
int i, j; | |
struct group *gr; | |
+#ifdef __APPLE_MEMBERSHIP__ | |
+ if (0 != mbr_uid_to_uuid(pw->pw_uid, u_uuid)) | |
+ return 0; | |
+#endif | |
+ | |
if (ngroups > 0) | |
ga_free(); | |
+#ifndef __APPLE_MEMBERSHIP__ | |
ngroups = NGROUPS_MAX; | |
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) | |
ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX)); | |
#endif | |
- | |
groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid)); | |
+#else | |
+ if (-1 == (ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid, | |
+ &groups_bygid))) { | |
+ logit("getgrouplist_2 failed"); | |
+ return 0; | |
+ } | |
+#endif | |
groups_byname = xcalloc(ngroups, sizeof(*groups_byname)); | |
- | |
- if (getgrouplist(user, base, groups_bygid, &ngroups) == -1) | |
- logit("getgrouplist: groups list too small"); | |
+#ifndef __APPLE_MEMBERSHIP__ | |
+ if (getgrouplist(pw->pw_name, pw->pw_gid, groups_bygid, &ngroups) == -1) { | |
+ logit("getgrouplist: groups list too small"); | |
+ free(groups_bygid); | |
+ return 0; | |
+ } | |
+#endif | |
for (i = 0, j = 0; i < ngroups; i++) | |
if ((gr = getgrgid(groups_bygid[i])) != NULL) | |
groups_byname[j++] = xstrdup(gr->gr_name); | |
@@ -76,16 +105,32 @@ ga_init(const char *user, gid_t base) | |
/* | |
* Return 1 if one of user's groups is contained in groups. | |
* Return 0 otherwise. Use match_pattern() for string comparison. | |
+ * Use mbr_check_membership() for membership checking on Mac OS X. | |
*/ | |
int | |
ga_match(char * const *groups, int n) | |
{ | |
+#ifdef __APPLE_MEMBERSHIP__ | |
+ int i, ismember = 0; | |
+ uuid_t g_uuid; | |
+ struct group *grp; | |
+ | |
+ for (i = 0; i < n; i++) { | |
+ if ((grp = getgrnam(groups[i])) == NULL || | |
+ (mbr_gid_to_uuid(grp->gr_gid, g_uuid) != 0) || | |
+ (mbr_check_membership(u_uuid, g_uuid, &ismember) != 0)) | |
+ return 0; | |
+ if (ismember) | |
+ return 1; | |
+ } | |
+#else | |
int i, j; | |
for (i = 0; i < ngroups; i++) | |
for (j = 0; j < n; j++) | |
if (match_pattern(groups_byname[i], groups[j])) | |
return 1; | |
+#endif | |
return 0; | |
} | |
diff --git a/groupaccess.h b/groupaccess.h | |
index 000578e..ddea117 100644 | |
--- a/groupaccess.h | |
+++ b/groupaccess.h | |
@@ -27,7 +27,7 @@ | |
#ifndef GROUPACCESS_H | |
#define GROUPACCESS_H | |
-int ga_init(const char *, gid_t); | |
+int ga_init(struct passwd *); | |
int ga_match(char * const *, int); | |
int ga_match_pattern_list(const char *); | |
void ga_free(void); | |
diff --git a/keychain.c b/keychain.c | |
new file mode 100644 | |
index 0000000..51d6ad9 | |
--- /dev/null | |
+++ b/keychain.c | |
@@ -0,0 +1,694 @@ | |
+/* | |
+ * Copyright (c) 2007 Apple Inc. All rights reserved. | |
+ * | |
+ * @APPLE_BSD_LICENSE_HEADER_START@ | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of its | |
+ * contributors may be used to endorse or promote products derived from | |
+ * this software without specific prior written permission. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
+ * | |
+ * @APPLE_BSD_LICENSE_HEADER_END@ | |
+ */ | |
+ | |
+#include "includes.h" | |
+ | |
+#include <stdio.h> | |
+#include <string.h> | |
+ | |
+#include "xmalloc.h" | |
+#include "key.h" | |
+#include "authfd.h" | |
+#include "authfile.h" | |
+ | |
+#if defined(__APPLE_KEYCHAIN__) | |
+ | |
+#include <CoreFoundation/CoreFoundation.h> | |
+#include <Security/Security.h> | |
+ | |
+/* Our Security/SecPassword.h is not yet API, so I will define the constants that I am using here. */ | |
+int kSecPasswordGet = 1<<0; // Get password from keychain or user | |
+int kSecPasswordSet = 1<<1; // Set password (passed in if kSecPasswordGet not set, otherwise from user) | |
+int kSecPasswordFail = 1<<2; // Wrong password (ignore item in keychain and flag error) | |
+OSStatus SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef); | |
+OSStatus SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data); | |
+OSStatus SecPasswordSetInitialAccess(SecPasswordRef itemRef, SecAccessRef accessRef); | |
+ | |
+#endif | |
+ | |
+/* | |
+ * Platform-specific helper functions. | |
+ */ | |
+ | |
+#if defined(__APPLE_KEYCHAIN__) | |
+ | |
+static int get_boolean_preference(const char *key, int default_value, | |
+ int foreground) | |
+{ | |
+ int value = default_value; | |
+ CFStringRef keyRef = NULL; | |
+ CFPropertyListRef valueRef = NULL; | |
+ | |
+ keyRef = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8); | |
+ if (keyRef != NULL) | |
+ valueRef = CFPreferencesCopyAppValue(keyRef, | |
+ CFSTR("org.openbsd.openssh")); | |
+ if (valueRef != NULL) | |
+ if (CFGetTypeID(valueRef) == CFBooleanGetTypeID()) | |
+ value = CFBooleanGetValue(valueRef); | |
+ else if (foreground) | |
+ fprintf(stderr, "Ignoring nonboolean %s preference.\n", key); | |
+ | |
+ if (keyRef) | |
+ CFRelease(keyRef); | |
+ if (valueRef) | |
+ CFRelease(valueRef); | |
+ | |
+ return value; | |
+} | |
+ | |
+#endif | |
+ | |
+/* | |
+ * Store the passphrase for a given identity in the keychain. | |
+ */ | |
+void | |
+store_in_keychain(const char *filename, const char *passphrase) | |
+{ | |
+ | |
+#if defined(__APPLE_KEYCHAIN__) | |
+ | |
+ /* | |
+ * store_in_keychain | |
+ * Mac OS X implementation | |
+ */ | |
+ | |
+ CFStringRef cfstr_relative_filename = NULL; | |
+ CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL; | |
+ CFStringRef cfstr_filename = NULL; | |
+ CFDataRef cfdata_filename = NULL; | |
+ CFIndex filename_len; | |
+ UInt8 *label = NULL; | |
+ UInt8 *utf8_filename; | |
+ OSStatus rv; | |
+ SecKeychainItemRef itemRef = NULL; | |
+ SecTrustedApplicationRef apps[] = {NULL, NULL, NULL}; | |
+ CFArrayRef trustedlist = NULL; | |
+ SecAccessRef initialAccess = NULL; | |
+ | |
+ /* Bail out if KeychainIntegration preference is -bool NO */ | |
+ if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) { | |
+ fprintf(stderr, "Keychain integration is disabled.\n"); | |
+ goto err; | |
+ } | |
+ | |
+ /* Interpret filename with the correct encoding. */ | |
+ if ((cfstr_relative_filename = | |
+ CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL) | |
+ { | |
+ fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL, | |
+ cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) { | |
+ fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) == | |
+ NULL) { | |
+ fprintf(stderr, "CFURLCopyAbsoluteURL failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename, | |
+ kCFURLPOSIXPathStyle)) == NULL) { | |
+ fprintf(stderr, "CFURLCopyFileSystemPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL, | |
+ cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) { | |
+ fprintf(stderr, "CFStringCreateExternalRepresentation failed\n"); | |
+ goto err; | |
+ } | |
+ filename_len = CFDataGetLength(cfdata_filename); | |
+ if ((label = xmalloc(filename_len + 5)) == NULL) { | |
+ fprintf(stderr, "xmalloc failed\n"); | |
+ goto err; | |
+ } | |
+ memcpy(label, "SSH: ", 5); | |
+ utf8_filename = label + 5; | |
+ CFDataGetBytes(cfdata_filename, CFRangeMake(0, filename_len), | |
+ utf8_filename); | |
+ | |
+ /* Check if we already have this passphrase. */ | |
+ rv = SecKeychainFindGenericPassword(NULL, 3, "SSH", filename_len, | |
+ (char *)utf8_filename, NULL, NULL, &itemRef); | |
+ if (rv == errSecItemNotFound) { | |
+ /* Add a new keychain item. */ | |
+ SecKeychainAttribute attrs[] = { | |
+ {kSecLabelItemAttr, filename_len + 5, label}, | |
+ {kSecServiceItemAttr, 3, "SSH"}, | |
+ {kSecAccountItemAttr, filename_len, utf8_filename} | |
+ }; | |
+ SecKeychainAttributeList attrList = | |
+ {sizeof(attrs) / sizeof(attrs[0]), attrs}; | |
+ if (SecTrustedApplicationCreateFromPath("/usr/bin/ssh-agent", | |
+ &apps[0]) != noErr || | |
+ SecTrustedApplicationCreateFromPath("/usr/bin/ssh-add", | |
+ &apps[1]) != noErr || | |
+ SecTrustedApplicationCreateFromPath("/usr/bin/ssh", | |
+ &apps[2]) != noErr) { | |
+ fprintf(stderr, "SecTrustedApplicationCreateFromPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((trustedlist = CFArrayCreate(NULL, (const void **)apps, | |
+ sizeof(apps) / sizeof(apps[0]), &kCFTypeArrayCallBacks)) == | |
+ NULL) { | |
+ fprintf(stderr, "CFArrayCreate failed\n"); | |
+ goto err; | |
+ } | |
+ if (SecAccessCreate(cfstr_filename, trustedlist, | |
+ &initialAccess) != noErr) { | |
+ fprintf(stderr, "SecAccessCreate failed\n"); | |
+ goto err; | |
+ } | |
+ if (SecKeychainItemCreateFromContent( | |
+ kSecGenericPasswordItemClass, &attrList, strlen(passphrase), | |
+ passphrase, NULL, initialAccess, NULL) == noErr) | |
+ fprintf(stderr, "Passphrase stored in keychain: %s\n", filename); | |
+ else | |
+ fprintf(stderr, "Could not create keychain item\n"); | |
+ } else if (rv == noErr) { | |
+ /* Update an existing keychain item. */ | |
+ if (SecKeychainItemModifyAttributesAndData(itemRef, NULL, | |
+ strlen(passphrase), passphrase) == noErr) | |
+ fprintf(stderr, "Passphrase updated in keychain: %s\n", filename); | |
+ else | |
+ fprintf(stderr, "Could not modify keychain item\n"); | |
+ } else | |
+ fprintf(stderr, "Could not access keychain\n"); | |
+ | |
+err: /* Clean up. */ | |
+ if (cfstr_relative_filename) | |
+ CFRelease(cfstr_relative_filename); | |
+ if (cfurl_relative_filename) | |
+ CFRelease(cfurl_relative_filename); | |
+ if (cfurl_filename) | |
+ CFRelease(cfurl_filename); | |
+ if (cfstr_filename) | |
+ CFRelease(cfstr_filename); | |
+ if (cfdata_filename) | |
+ CFRelease(cfdata_filename); | |
+ if (label) | |
+ free(label); | |
+ if (itemRef) | |
+ CFRelease(itemRef); | |
+ if (apps[0]) | |
+ CFRelease(apps[0]); | |
+ if (apps[1]) | |
+ CFRelease(apps[1]); | |
+ if (apps[2]) | |
+ CFRelease(apps[2]); | |
+ if (trustedlist) | |
+ CFRelease(trustedlist); | |
+ if (initialAccess) | |
+ CFRelease(initialAccess); | |
+ | |
+#else | |
+ | |
+ /* | |
+ * store_in_keychain | |
+ * no keychain implementation | |
+ */ | |
+ | |
+ fprintf(stderr, "Keychain is not available on this system\n"); | |
+ | |
+#endif | |
+ | |
+} | |
+ | |
+/* | |
+ * Remove the passphrase for a given identity from the keychain. | |
+ */ | |
+void | |
+remove_from_keychain(const char *filename) | |
+{ | |
+ | |
+#if defined(__APPLE_KEYCHAIN__) | |
+ | |
+ /* | |
+ * remove_from_keychain | |
+ * Mac OS X implementation | |
+ */ | |
+ | |
+ CFStringRef cfstr_relative_filename = NULL; | |
+ CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL; | |
+ CFStringRef cfstr_filename = NULL; | |
+ CFDataRef cfdata_filename = NULL; | |
+ CFIndex filename_len; | |
+ const UInt8 *utf8_filename; | |
+ OSStatus rv; | |
+ SecKeychainItemRef itemRef = NULL; | |
+ | |
+ /* Bail out if KeychainIntegration preference is -bool NO */ | |
+ if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) { | |
+ fprintf(stderr, "Keychain integration is disabled.\n"); | |
+ goto err; | |
+ } | |
+ | |
+ /* Interpret filename with the correct encoding. */ | |
+ if ((cfstr_relative_filename = | |
+ CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL) | |
+ { | |
+ fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL, | |
+ cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) { | |
+ fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) == | |
+ NULL) { | |
+ fprintf(stderr, "CFURLCopyAbsoluteURL failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename, | |
+ kCFURLPOSIXPathStyle)) == NULL) { | |
+ fprintf(stderr, "CFURLCopyFileSystemPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL, | |
+ cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) { | |
+ fprintf(stderr, "CFStringCreateExternalRepresentation failed\n"); | |
+ goto err; | |
+ } | |
+ filename_len = CFDataGetLength(cfdata_filename); | |
+ utf8_filename = CFDataGetBytePtr(cfdata_filename); | |
+ | |
+ /* Check if we already have this passphrase. */ | |
+ rv = SecKeychainFindGenericPassword(NULL, 3, "SSH", filename_len, | |
+ (const char *)utf8_filename, NULL, NULL, &itemRef); | |
+ if (rv == noErr) { | |
+ /* Remove the passphrase from the keychain. */ | |
+ if (SecKeychainItemDelete(itemRef) == noErr) | |
+ fprintf(stderr, "Passphrase removed from keychain: %s\n", filename); | |
+ else | |
+ fprintf(stderr, "Could not remove keychain item\n"); | |
+ } else if (rv != errSecItemNotFound) | |
+ fprintf(stderr, "Could not access keychain\n"); | |
+ | |
+err: /* Clean up. */ | |
+ if (cfstr_relative_filename) | |
+ CFRelease(cfstr_relative_filename); | |
+ if (cfurl_relative_filename) | |
+ CFRelease(cfurl_relative_filename); | |
+ if (cfurl_filename) | |
+ CFRelease(cfurl_filename); | |
+ if (cfstr_filename) | |
+ CFRelease(cfstr_filename); | |
+ if (cfdata_filename) | |
+ CFRelease(cfdata_filename); | |
+ if (itemRef) | |
+ CFRelease(itemRef); | |
+ | |
+#else | |
+ | |
+ /* | |
+ * remove_from_keychain | |
+ * no keychain implementation | |
+ */ | |
+ | |
+ fprintf(stderr, "Keychain is not available on this system\n"); | |
+ | |
+#endif | |
+ | |
+} | |
+ | |
+/* | |
+ * Add identities to ssh-agent using passphrases stored in the keychain. | |
+ * Returns zero on success and nonzero on failure. | |
+ * add_identity is a callback into ssh-agent. It takes a filename and a | |
+ * passphrase, and attempts to add the identity to the agent. It returns | |
+ * zero on success and nonzero on failure. | |
+ */ | |
+int | |
+add_identities_using_keychain(int (*add_identity)(const char *, const char *)) | |
+{ | |
+ | |
+#if defined(__APPLE_KEYCHAIN__) | |
+ | |
+ /* | |
+ * add_identities_using_keychain | |
+ * Mac OS X implementation | |
+ */ | |
+ | |
+ OSStatus rv; | |
+ SecKeychainSearchRef searchRef; | |
+ SecKeychainItemRef itemRef; | |
+ UInt32 length; | |
+ void *data; | |
+ CFIndex maxsize; | |
+ | |
+ /* Bail out if KeychainIntegration preference is -bool NO */ | |
+ if (get_boolean_preference("KeychainIntegration", 1, 0) == 0) | |
+ return 0; | |
+ | |
+ /* Search for SSH passphrases in the keychain */ | |
+ SecKeychainAttribute attrs[] = { | |
+ {kSecServiceItemAttr, 3, "SSH"} | |
+ }; | |
+ SecKeychainAttributeList attrList = | |
+ {sizeof(attrs) / sizeof(attrs[0]), attrs}; | |
+ if ((rv = SecKeychainSearchCreateFromAttributes(NULL, | |
+ kSecGenericPasswordItemClass, &attrList, &searchRef)) != noErr) | |
+ return 0; | |
+ | |
+ /* Iterate through the search results. */ | |
+ while ((rv = SecKeychainSearchCopyNext(searchRef, &itemRef)) == noErr) { | |
+ UInt32 tag = kSecAccountItemAttr; | |
+ UInt32 format = kSecFormatUnknown; | |
+ SecKeychainAttributeInfo info = {1, &tag, &format}; | |
+ SecKeychainAttributeList *itemAttrList = NULL; | |
+ CFStringRef cfstr_filename = NULL; | |
+ char *filename = NULL; | |
+ char *passphrase = NULL; | |
+ | |
+ /* Retrieve filename and passphrase. */ | |
+ if ((rv = SecKeychainItemCopyAttributesAndData(itemRef, &info, | |
+ NULL, &itemAttrList, &length, &data)) != noErr) | |
+ goto err; | |
+ if (itemAttrList->count != 1) | |
+ goto err; | |
+ cfstr_filename = CFStringCreateWithBytes(NULL, | |
+ itemAttrList->attr->data, itemAttrList->attr->length, | |
+ kCFStringEncodingUTF8, true); | |
+ maxsize = CFStringGetMaximumSizeOfFileSystemRepresentation( | |
+ cfstr_filename); | |
+ if ((filename = xmalloc(maxsize)) == NULL) | |
+ goto err; | |
+ if (CFStringGetFileSystemRepresentation(cfstr_filename, | |
+ filename, maxsize) == false) | |
+ goto err; | |
+ if ((passphrase = xmalloc(length + 1)) == NULL) | |
+ goto err; | |
+ memcpy(passphrase, data, length); | |
+ passphrase[length] = '\0'; | |
+ | |
+ /* Add the identity. */ | |
+ add_identity(filename, passphrase); | |
+ | |
+err: /* Clean up. */ | |
+ if (itemRef) | |
+ CFRelease(itemRef); | |
+ if (cfstr_filename) | |
+ CFRelease(cfstr_filename); | |
+ if (filename) | |
+ free(filename); | |
+ if (passphrase) | |
+ free(passphrase); | |
+ if (itemAttrList) | |
+ SecKeychainItemFreeAttributesAndData(itemAttrList, | |
+ data); | |
+ } | |
+ | |
+ CFRelease(searchRef); | |
+ | |
+ return 0; | |
+ | |
+#else | |
+ | |
+ /* | |
+ * add_identities_using_keychain | |
+ * no implementation | |
+ */ | |
+ | |
+ return 1; | |
+ | |
+#endif | |
+ | |
+} | |
+ | |
+/* | |
+ * Prompt the user for a key's passphrase. The user will be offered the option | |
+ * of storing the passphrase in their keychain. Returns the passphrase | |
+ * (which the caller is responsible for freeing), or NULL if this function | |
+ * fails or is not implemented. If this function is not implemented, ssh will | |
+ * fall back on the standard read_passphrase function, and the user will need | |
+ * to use ssh-add -K to add their keys to the keychain. | |
+ */ | |
+char * | |
+keychain_read_passphrase(const char *filename, int oAskPassGUI) | |
+{ | |
+ | |
+#if defined(__APPLE_KEYCHAIN__) | |
+ | |
+ /* | |
+ * keychain_read_passphrase | |
+ * Mac OS X implementation | |
+ */ | |
+ | |
+ CFStringRef cfstr_relative_filename = NULL; | |
+ CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL; | |
+ CFStringRef cfstr_filename = NULL; | |
+ CFDataRef cfdata_filename = NULL; | |
+ CFIndex filename_len; | |
+ UInt8 *label = NULL; | |
+ UInt8 *utf8_filename; | |
+ SecPasswordRef passRef = NULL; | |
+ SecTrustedApplicationRef apps[] = {NULL, NULL, NULL}; | |
+ CFArrayRef trustedlist = NULL; | |
+ SecAccessRef initialAccess = NULL; | |
+ CFURLRef path = NULL; | |
+ CFStringRef pathFinal = NULL; | |
+ CFURLRef bundle_url = NULL; | |
+ CFBundleRef bundle = NULL; | |
+ CFStringRef promptTemplate = NULL, prompt = NULL; | |
+ UInt32 length; | |
+ const void *data; | |
+ int sock = -1; | |
+ char *result = NULL; | |
+ | |
+ /* Bail out if KeychainIntegration preference is -bool NO */ | |
+ if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) | |
+ goto err; | |
+ | |
+ /* Bail out if the user set AskPassGUI preference to -bool NO */ | |
+ if (get_boolean_preference("AskPassGUI", 1, 1) == 0 || oAskPassGUI == 0) | |
+ goto err; | |
+ | |
+ /* Bail out if we can't communicate with ssh-agent */ | |
+ if ((ssh_get_authentication_socket(&sock)) != 0) | |
+ goto err; | |
+ | |
+ /* Interpret filename with the correct encoding. */ | |
+ if ((cfstr_relative_filename = | |
+ CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL) | |
+ { | |
+ fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL, | |
+ cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) { | |
+ fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) == | |
+ NULL) { | |
+ fprintf(stderr, "CFURLCopyAbsoluteURL failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename, | |
+ kCFURLPOSIXPathStyle)) == NULL) { | |
+ fprintf(stderr, "CFURLCopyFileSystemPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL, | |
+ cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) { | |
+ fprintf(stderr, "CFStringCreateExternalRepresentation failed\n"); | |
+ goto err; | |
+ } | |
+ filename_len = CFDataGetLength(cfdata_filename); | |
+ if ((label = xmalloc(filename_len + 5)) == NULL) { | |
+ fprintf(stderr, "xmalloc failed\n"); | |
+ goto err; | |
+ } | |
+ memcpy(label, "SSH: ", 5); | |
+ utf8_filename = label + 5; | |
+ CFDataGetBytes(cfdata_filename, CFRangeMake(0, filename_len), | |
+ utf8_filename); | |
+ | |
+ /* Build a SecPasswordRef. */ | |
+ SecKeychainAttribute searchAttrs[] = { | |
+ {kSecServiceItemAttr, 3, "SSH"}, | |
+ {kSecAccountItemAttr, filename_len, utf8_filename} | |
+ }; | |
+ SecKeychainAttributeList searchAttrList = | |
+ {sizeof(searchAttrs) / sizeof(searchAttrs[0]), searchAttrs}; | |
+ SecKeychainAttribute attrs[] = { | |
+ {kSecLabelItemAttr, filename_len + 5, label}, | |
+ {kSecServiceItemAttr, 3, "SSH"}, | |
+ {kSecAccountItemAttr, filename_len, utf8_filename} | |
+ }; | |
+ SecKeychainAttributeList attrList = | |
+ {sizeof(attrs) / sizeof(attrs[0]), attrs}; | |
+ if (SecGenericPasswordCreate(&searchAttrList, &attrList, &passRef) != | |
+ noErr) { | |
+ fprintf(stderr, "SecGenericPasswordCreate failed\n"); | |
+ goto err; | |
+ } | |
+ if (SecTrustedApplicationCreateFromPath("/usr/bin/ssh-agent", &apps[0]) | |
+ != noErr || | |
+ SecTrustedApplicationCreateFromPath("/usr/bin/ssh-add", &apps[1]) | |
+ != noErr || | |
+ SecTrustedApplicationCreateFromPath("/usr/bin/ssh", &apps[2]) | |
+ != noErr) { | |
+ fprintf(stderr, "SecTrustedApplicationCreateFromPath failed\n"); | |
+ goto err; | |
+ } | |
+ if ((trustedlist = CFArrayCreate(NULL, (const void **)apps, | |
+ sizeof(apps) / sizeof(apps[0]), &kCFTypeArrayCallBacks)) == NULL) { | |
+ fprintf(stderr, "CFArrayCreate failed\n"); | |
+ goto err; | |
+ } | |
+ if (SecAccessCreate(cfstr_filename, trustedlist, &initialAccess) | |
+ != noErr) { | |
+ fprintf(stderr, "SecAccessCreate failed\n"); | |
+ goto err; | |
+ } | |
+ if (SecPasswordSetInitialAccess(passRef, initialAccess) != noErr) { | |
+ fprintf(stderr, "SecPasswordSetInitialAccess failed\n"); | |
+ goto err; | |
+ } | |
+ | |
+ /* Request the passphrase from the user. */ | |
+ if ((path = CFURLCreateFromFileSystemRepresentation(NULL, | |
+ (UInt8 *)filename, strlen(filename), false)) == NULL) { | |
+ fprintf(stderr, "CFURLCreateFromFileSystemRepresentation failed\n"); | |
+ goto err; | |
+ } | |
+ if ((pathFinal = CFURLCopyLastPathComponent(path)) == NULL) { | |
+ fprintf(stderr, "CFURLCopyLastPathComponent failed\n"); | |
+ goto err; | |
+ } | |
+ if (!((bundle_url = CFURLCreateWithFileSystemPath(NULL, | |
+ CFSTR("/System/Library/CoreServices/"), kCFURLPOSIXPathStyle, true)) | |
+ != NULL && (bundle = CFBundleCreate(NULL, bundle_url)) != NULL && | |
+ (promptTemplate = CFCopyLocalizedStringFromTableInBundle( | |
+ CFSTR("Enter your password for the SSH key \"%@\"."), | |
+ CFSTR("OpenSSH"), bundle, "Text of the dialog asking the user for" | |
+ "their passphrase. The %@ will be replaced with the filename of a" | |
+ "specific key.")) != NULL) && | |
+ (promptTemplate = CFStringCreateCopy(NULL, | |
+ CFSTR("Enter your password for the SSH key \"%@\"."))) == NULL) { | |
+ fprintf(stderr, "CFStringCreateCopy failed\n"); | |
+ goto err; | |
+ } | |
+ if ((prompt = CFStringCreateWithFormat(NULL, NULL, promptTemplate, | |
+ pathFinal)) == NULL) { | |
+ fprintf(stderr, "CFStringCreateWithFormat failed\n"); | |
+ goto err; | |
+ } | |
+ switch (SecPasswordAction(passRef, prompt, | |
+ kSecPasswordGet|kSecPasswordFail, &length, &data)) { | |
+ case noErr: | |
+ result = xmalloc(length + 1); | |
+ memcpy(result, data, length); | |
+ result[length] = '\0'; | |
+ | |
+ /* Save password in keychain if requested. */ | |
+ if (noErr != SecPasswordAction(passRef, CFSTR(""), kSecPasswordSet, &length, &data)) | |
+ fprintf(stderr, "Saving password to keychain failed\n"); | |
+ | |
+ /* Add password to agent. */ | |
+ char *comment = NULL; | |
+ Key *private = key_load_private(filename, result, &comment); | |
+ if (NULL == private) | |
+ break; | |
+ if (ssh_add_identity_constrained(sock, private, comment, 0, 0)) | |
+ fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); | |
+ else | |
+ fprintf(stderr, "Could not add identity: %s\n", filename); | |
+ free(comment); | |
+ key_free(private); | |
+ break; | |
+ case errAuthorizationCanceled: | |
+ result = xmalloc(1); | |
+ *result = '\0'; | |
+ break; | |
+ default: | |
+ goto err; | |
+ } | |
+ | |
+err: /* Clean up. */ | |
+ if (cfstr_relative_filename) | |
+ CFRelease(cfstr_relative_filename); | |
+ if (cfurl_relative_filename) | |
+ CFRelease(cfurl_relative_filename); | |
+ if (cfurl_filename) | |
+ CFRelease(cfurl_filename); | |
+ if (cfstr_filename) | |
+ CFRelease(cfstr_filename); | |
+ if (cfdata_filename) | |
+ CFRelease(cfdata_filename); | |
+ if (label) | |
+ free(label); | |
+ if (passRef) | |
+ CFRelease(passRef); | |
+ if (apps[0]) | |
+ CFRelease(apps[0]); | |
+ if (apps[1]) | |
+ CFRelease(apps[1]); | |
+ if (apps[2]) | |
+ CFRelease(apps[2]); | |
+ if (trustedlist) | |
+ CFRelease(trustedlist); | |
+ if (initialAccess) | |
+ CFRelease(initialAccess); | |
+ if (path) | |
+ CFRelease(path); | |
+ if (pathFinal) | |
+ CFRelease(pathFinal); | |
+ if (bundle_url) | |
+ CFRelease(bundle_url); | |
+ if (bundle) | |
+ CFRelease(bundle); | |
+ if (promptTemplate) | |
+ CFRelease(promptTemplate); | |
+ if (prompt) | |
+ CFRelease(prompt); | |
+ if (sock != -1) | |
+ ssh_close_authentication_socket(sock); | |
+ | |
+ return result; | |
+ | |
+#else | |
+ | |
+ /* | |
+ * keychain_read_passphrase | |
+ * no implementation | |
+ */ | |
+ | |
+ return NULL; | |
+ | |
+#endif | |
+ | |
+} | |
diff --git a/keychain.h b/keychain.h | |
new file mode 100644 | |
index 0000000..9bb8c22 | |
--- /dev/null | |
+++ b/keychain.h | |
@@ -0,0 +1,45 @@ | |
+/* | |
+ * Copyright (c) 2007 Apple Inc. All rights reserved. | |
+ * | |
+ * @APPLE_BSD_LICENSE_HEADER_START@ | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of its | |
+ * contributors may be used to endorse or promote products derived from | |
+ * this software without specific prior written permission. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
+ * | |
+ * @APPLE_BSD_LICENSE_HEADER_END@ | |
+ */ | |
+ | |
+/* | |
+ * KEYCHAIN indicates that keychain functionality is present. | |
+ * KEYCHAIN_* indicates the implementation to use, and implies KEYCHAIN. | |
+ */ | |
+#if defined(__APPLE_KEYCHAIN__) | |
+#define KEYCHAIN | |
+#endif | |
+ | |
+void store_in_keychain(const char *filename, const char *passphrase); | |
+void remove_from_keychain(const char *filename); | |
+int add_identities_using_keychain( | |
+ int (*add_identity)(const char *, const char *)); | |
+char *keychain_read_passphrase(const char *filename, int oAskPassGUI); | |
diff --git a/readconf.c b/readconf.c | |
index 9d59493..48f1ab6 100644 | |
--- a/readconf.c | |
+++ b/readconf.c | |
@@ -168,6 +168,9 @@ typedef enum { | |
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, | |
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, | |
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ oAskPassGUI, | |
+#endif | |
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, | |
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, | |
oPubkeyAcceptedKeyTypes, oProxyJump, | |
@@ -308,6 +311,9 @@ static struct { | |
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, | |
{ "ignoreunknown", oIgnoreUnknown }, | |
{ "proxyjump", oProxyJump }, | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ { "askpassgui", oAskPassGUI }, | |
+#endif | |
{ NULL, oBadOption } | |
}; | |
@@ -1562,6 +1568,12 @@ parse_keytypes: | |
charptr = &options->ignored_unknown; | |
goto parse_string; | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ case oAskPassGUI: | |
+ intptr = &options->ask_pass_gui; | |
+ goto parse_flag; | |
+#endif | |
+ | |
case oProxyUseFdpass: | |
intptr = &options->proxy_use_fdpass; | |
goto parse_flag; | |
@@ -1869,6 +1881,9 @@ initialize_options(Options * options) | |
options->request_tty = -1; | |
options->proxy_use_fdpass = -1; | |
options->ignored_unknown = NULL; | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ options->ask_pass_gui = -1; | |
+#endif | |
options->num_canonical_domains = 0; | |
options->num_permitted_cnames = 0; | |
options->canonicalize_max_dots = -1; | |
@@ -2054,6 +2069,10 @@ fill_default_options(Options * options) | |
options->ip_qos_bulk = IPTOS_THROUGHPUT; | |
if (options->request_tty == -1) | |
options->request_tty = REQUEST_TTY_AUTO; | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ if (options->ask_pass_gui == -1) | |
+ options->ask_pass_gui = 1; | |
+#endif | |
if (options->proxy_use_fdpass == -1) | |
options->proxy_use_fdpass = 0; | |
if (options->canonicalize_max_dots == -1) | |
diff --git a/readconf.h b/readconf.h | |
index cef55f7..913c938 100644 | |
--- a/readconf.h | |
+++ b/readconf.h | |
@@ -169,6 +169,10 @@ typedef struct { | |
char *jump_extra; | |
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ | |
+ | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ int ask_pass_gui; | |
+#endif | |
} Options; | |
#define SSH_CANONICALISE_NO 0 | |
diff --git a/scp.1 b/scp.1 | |
index 4ae8777..3535932 100644 | |
--- a/scp.1 | |
+++ b/scp.1 | |
@@ -19,7 +19,7 @@ | |
.Sh SYNOPSIS | |
.Nm scp | |
.Bk -words | |
-.Op Fl 12346BCpqrv | |
+.Op Fl 12346BCEpqrv | |
.Op Fl c Ar cipher | |
.Op Fl F Ar ssh_config | |
.Op Fl i Ar identity_file | |
@@ -95,6 +95,8 @@ Passes the | |
flag to | |
.Xr ssh 1 | |
to enable compression. | |
+.It Fl E | |
+Preserves extended attributes, resource forks, and ACLs. Requires both ends to be running Mac OS X 10.4 or later. | |
.It Fl c Ar cipher | |
Selects the cipher to use for encrypting the data transfer. | |
This option is directly passed to | |
diff --git a/scp.c b/scp.c | |
index b4db851..7eeb9e3 100644 | |
--- a/scp.c | |
+++ b/scp.c | |
@@ -77,6 +77,9 @@ | |
#ifdef HAVE_SYS_STAT_H | |
# include <sys/stat.h> | |
#endif | |
+#ifdef __APPLE_XSAN__ | |
+#include <sys/mount.h> | |
+#endif | |
#ifdef HAVE_POLL_H | |
#include <poll.h> | |
#else | |
@@ -116,6 +119,11 @@ | |
#include "progressmeter.h" | |
#include "utf8.h" | |
+#ifdef HAVE_COPYFILE_H | |
+#include <libgen.h> | |
+#include <copyfile.h> | |
+#endif | |
+ | |
extern char *__progname; | |
#define COPY_BUFLEN 16384 | |
@@ -152,6 +160,12 @@ char *ssh_program = _PATH_SSH_PROGRAM; | |
/* This is used to store the pid of ssh_program */ | |
pid_t do_cmd_pid = -1; | |
+#ifdef HAVE_COPYFILE | |
+int copy_xattr = 0; | |
+int md_flag = 0; | |
+#endif | |
+ | |
+ | |
static void | |
killchild(int signo) | |
{ | |
@@ -399,7 +413,11 @@ main(int argc, char **argv) | |
addargs(&args, "-oClearAllForwardings=yes"); | |
fflag = tflag = 0; | |
+#if HAVE_COPYFILE | |
+ while ((ch = getopt(argc, argv, "dfl:prtvBCEc:i:P:q12346S:o:F:")) != -1) | |
+#else | |
while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) | |
+#endif | |
switch (ch) { | |
/* User-visible flags. */ | |
case '1': | |
@@ -460,6 +478,11 @@ main(int argc, char **argv) | |
showprogress = 0; | |
break; | |
+#ifdef HAVE_COPYFILE | |
+ case 'E': | |
+ copy_xattr = 1; | |
+ break; | |
+#endif | |
/* Server options. */ | |
case 'd': | |
targetshouldbedirectory = 1; | |
@@ -519,7 +542,12 @@ main(int argc, char **argv) | |
remin = remout = -1; | |
do_cmd_pid = -1; | |
/* Command to be executed on remote system using "ssh". */ | |
+#if HAVE_COPYFILE | |
+ (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s%s", | |
+ copy_xattr ? " -E" : "", | |
+#else | |
(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", | |
+#endif | |
verbose_mode ? " -v" : "", | |
iamrecursive ? " -r" : "", pflag ? " -p" : "", | |
targetshouldbedirectory ? " -d" : ""); | |
@@ -765,6 +793,10 @@ source(int argc, char **argv) | |
int fd = -1, haderr, indx; | |
char *last, *name, buf[2048], encname[PATH_MAX]; | |
int len; | |
+#if HAVE_COPYFILE | |
+ char md_name[MAXPATHLEN]; | |
+ char *md_tmp; | |
+#endif | |
for (indx = 0; indx < argc; ++indx) { | |
name = argv[indx]; | |
@@ -772,12 +804,26 @@ source(int argc, char **argv) | |
len = strlen(name); | |
while (len > 1 && name[len-1] == '/') | |
name[--len] = '\0'; | |
+#if HAVE_COPYFILE | |
+md_next: | |
+ statbytes = 0; | |
+ if (md_flag) { | |
+ fd = open(md_tmp, O_RDONLY, 0); | |
+ unlink(md_tmp); | |
+ free(md_tmp); | |
+ if (fd < 0) | |
+ goto syserr; | |
+ } else { | |
+#endif | |
if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0) | |
goto syserr; | |
if (strchr(name, '\n') != NULL) { | |
strnvis(encname, name, sizeof(encname), VIS_NL); | |
name = encname; | |
} | |
+#if HAVE_COPYFILE | |
+ } | |
+#endif | |
if (fstat(fd, &stb) < 0) { | |
syserr: run_err("%s: %s", name, strerror(errno)); | |
goto next; | |
@@ -861,6 +907,36 @@ next: if (fd != -1) { | |
else | |
run_err("%s: %s", name, strerror(haderr)); | |
(void) response(); | |
+#ifdef HAVE_COPYFILE | |
+ if (copy_xattr && md_flag == 0) | |
+ { | |
+ if (!copyfile(name, NULL, 0, | |
+ COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_CHECK)) | |
+ continue; | |
+ | |
+ /* | |
+ * this file will hold the actual metadata | |
+ * to be transferred | |
+ */ | |
+ md_tmp = strdup("/tmp/scp.md.XXXXXX"); | |
+ md_tmp = mktemp(md_tmp); | |
+ | |
+ if(copyfile(name, md_tmp, 0, | |
+ COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_PACK) == 0) | |
+ { | |
+ /* | |
+ * this is the fake name to display | |
+ */ | |
+ snprintf(md_name, sizeof md_name, "%s/._%s", dirname(name), basename(name)); | |
+ name = md_name; | |
+ md_flag = 1; | |
+ if (verbose_mode) | |
+ fprintf(stderr, "copyfile(%s, %s, PACK)\n", name, md_tmp); | |
+ goto md_next; | |
+ } | |
+ } else | |
+ md_flag = 0; | |
+#endif | |
if (showprogress) | |
stop_progress_meter(); | |
} | |
@@ -954,6 +1030,10 @@ sink(int argc, char **argv) | |
if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) | |
targisdir = 1; | |
for (first = 1;; first = 0) { | |
+#if HAVE_COPYFILE | |
+ char md_src[MAXPATHLEN]; | |
+ char md_dst[MAXPATHLEN]; | |
+#endif | |
cp = buf; | |
if (atomicio(read, remin, cp, 1) != 1) | |
return; | |
@@ -1102,10 +1182,51 @@ sink(int argc, char **argv) | |
} | |
omode = mode; | |
mode |= S_IWUSR; | |
+ | |
+#if HAVE_COPYFILE | |
+ if (copy_xattr && !strncmp(basename(curfile), "._", 2)) | |
+ { | |
+ int mdfd; | |
+ if (targisdir) | |
+ { | |
+ snprintf(md_src, sizeof md_src, "%s.XXXXXX", np); | |
+ snprintf(md_dst, sizeof md_dst, "%s/%s", | |
+ dirname(np), basename(np) + 2); | |
+ if((mdfd = mkstemp(md_src)) < 0) | |
+ continue; | |
+ } | |
+ else | |
+ { | |
+ snprintf(md_src, sizeof md_src, "%s/._%s.XXXXXX", | |
+ dirname(np), basename(np)); | |
+ snprintf(md_dst, sizeof md_dst, "%s", np); | |
+ if((mdfd = mkstemp(md_src)) < 0) | |
+ continue; | |
+ } | |
+ if (mdfd >= 0) | |
+ close(mdfd); | |
+ np = md_src; | |
+ } | |
+#endif | |
if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { | |
bad: run_err("%s: %s", np, strerror(errno)); | |
continue; | |
} | |
+#ifdef __APPLE_XSAN__ | |
+ { | |
+ /* | |
+ * Pre-allocate blocks for the destination file. | |
+ */ | |
+ fstore_t fst; | |
+ | |
+ fst.fst_flags = 0; | |
+ fst.fst_posmode = F_PEOFPOSMODE; | |
+ fst.fst_offset = 0; | |
+ fst.fst_length = size; | |
+ | |
+ (void) fcntl(ofd, F_PREALLOCATE, &fst); | |
+ } | |
+#endif /* __APPLE_XSAN__ */ | |
(void) atomicio(vwrite, remout, "", 1); | |
if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) { | |
(void) close(ofd); | |
@@ -1188,6 +1309,29 @@ bad: run_err("%s: %s", np, strerror(errno)); | |
wrerrno = errno; | |
} | |
(void) response(); | |
+#ifdef HAVE_COPYFILE | |
+ if (copy_xattr && strncmp(basename(np), "._", 2) == 0) | |
+ { | |
+ if (verbose_mode) | |
+ fprintf(stderr, "copyfile(%s, %s, UNPACK)\n", md_src, md_dst); | |
+ if(!copyfile(md_src, md_dst, 0, | |
+ COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_UNPACK) < 0) | |
+ { | |
+ snprintf(md_dst, sizeof md_dst, "%s/._%s", | |
+ dirname(md_dst), basename(md_dst)); | |
+ rename(md_src, md_dst); | |
+ } else | |
+ unlink(md_src); | |
+ if (setimes && wrerr == NO) { | |
+ setimes = 0; | |
+ if (utimes(md_dst, tv) < 0) { | |
+ run_err("%s: set times: %s", | |
+ np, strerror(errno)); | |
+ wrerr = DISPLAYED; | |
+ } | |
+ } | |
+ } else | |
+#endif | |
if (showprogress) | |
stop_progress_meter(); | |
if (setimes && wrerr == NO) { | |
@@ -1256,7 +1400,11 @@ void | |
usage(void) | |
{ | |
(void) fprintf(stderr, | |
+#if HAVE_COPYFILE | |
+ "usage: scp [-12346BCEpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" | |
+#else | |
"usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" | |
+#endif | |
" [-l limit] [-o ssh_option] [-P port] [-S program]\n" | |
" [[user@]host1:]file1 ... [[user@]host2:]file2\n"); | |
exit(1); | |
diff --git a/servconf.c b/servconf.c | |
index 56b8316..0c2680c 100644 | |
--- a/servconf.c | |
+++ b/servconf.c | |
@@ -272,7 +272,7 @@ fill_default_server_options(ServerOptions *options) | |
if (options->gss_strict_acceptor == -1) | |
options->gss_strict_acceptor = 1; | |
if (options->password_authentication == -1) | |
- options->password_authentication = 1; | |
+ options->password_authentication = 0; | |
if (options->kbd_interactive_authentication == -1) | |
options->kbd_interactive_authentication = 0; | |
if (options->challenge_response_authentication == -1) | |
@@ -752,7 +752,7 @@ match_cfg_line_group(const char *grps, int line, const char *user) | |
if ((pw = getpwnam(user)) == NULL) { | |
debug("Can't match group at line %d because user %.100s does " | |
"not exist", line, user); | |
- } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) { | |
+ } else if (ga_init(pw) == 0) { | |
debug("Can't Match group because user %.100s not in any group " | |
"at line %d", user, line); | |
} else if (ga_match_pattern_list(grps) != 1) { | |
diff --git a/session.c b/session.c | |
index a08aa69..43142f1 100644 | |
--- a/session.c | |
+++ b/session.c | |
@@ -1902,8 +1902,10 @@ session_pty_req(Session *s) | |
n_bytes = packet_remaining(); | |
tty_parse_modes(s->ttyfd, &n_bytes); | |
+#ifndef __APPLE_PRIVPTY__ | |
if (!use_privsep) | |
pty_setowner(s->pw, s->tty); | |
+#endif | |
/* Set window size from the packet. */ | |
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); | |
@@ -2147,9 +2149,11 @@ session_pty_cleanup2(Session *s) | |
if (s->pid != 0) | |
record_logout(s->pid, s->tty, s->pw->pw_name); | |
+#ifndef __APPLE_PRIVPTY__ | |
/* Release the pseudo-tty. */ | |
if (getuid() == 0) | |
pty_release(s->tty); | |
+#endif | |
/* | |
* Close the server side of the socket pairs. We must do this after | |
diff --git a/ssh-add.0 b/ssh-add.0 | |
index 706bfe6..429e4e7 100644 | |
--- a/ssh-add.0 | |
+++ b/ssh-add.0 | |
@@ -4,7 +4,7 @@ NAME | |
ssh-add M-bM-^@M-^S adds private key identities to the authentication agent | |
SYNOPSIS | |
- ssh-add [-cDdkLlXx] [-E fingerprint_hash] [-t life] [file ...] | |
+ ssh-add [-cDdkKLlXx] [-E fingerprint_hash] [-t life] [file ...] | |
ssh-add -s pkcs11 | |
ssh-add -e pkcs11 | |
@@ -60,6 +60,13 @@ DESCRIPTION | |
-l Lists fingerprints of all identities currently represented by the | |
agent. | |
+ -m Add identities to the agent using any passphrases stored in your | |
+ Mac OS X keychain. | |
+ | |
+ -M When adding identities, each passphrase will also be stored in | |
+ your Mac OS X keychain. When removing identities with -d, each | |
+ passphrase will be removed from your Mac OS X keychain. | |
+ | |
-s pkcs11 | |
Add keys provided by the PKCS#11 shared library pkcs11. | |
diff --git a/ssh-add.1 b/ssh-add.1 | |
index f02b595..d53b956 100644 | |
--- a/ssh-add.1 | |
+++ b/ssh-add.1 | |
@@ -43,7 +43,7 @@ | |
.Nd adds private key identities to the authentication agent | |
.Sh SYNOPSIS | |
.Nm ssh-add | |
-.Op Fl cDdkLlXx | |
+.Op Fl cDdkLlMmXx | |
.Op Fl E Ar fingerprint_hash | |
.Op Fl t Ar life | |
.Op Ar | |
@@ -127,6 +127,13 @@ Lists public key parameters of all identities currently represented | |
by the agent. | |
.It Fl l | |
Lists fingerprints of all identities currently represented by the agent. | |
+.It Fl m | |
+Add identities to the agent using any passphrases stored in your Mac OS | |
+X keychain. | |
+.It Fl M | |
+When adding identities, each passphrase will also be stored in your Mac OS | |
+Xkeychain. When removing identities with -d, each passphrase will be removed | |
+from your Mac OS X keychain. | |
.It Fl s Ar pkcs11 | |
Add keys provided by the PKCS#11 shared library | |
.Ar pkcs11 . | |
diff --git a/ssh-add.c b/ssh-add.c | |
index fb9a53e..0febac0 100644 | |
--- a/ssh-add.c | |
+++ b/ssh-add.c | |
@@ -65,6 +65,7 @@ | |
#include "misc.h" | |
#include "ssherr.h" | |
#include "digest.h" | |
+#include "keychain.h" | |
/* argv0 */ | |
extern char *__progname; | |
@@ -106,12 +107,25 @@ clear_pass(void) | |
} | |
static int | |
-delete_file(int agent_fd, const char *filename, int key_only) | |
+add_from_keychain(int agent_fd) | |
+{ | |
+ if (ssh_add_from_keychain(agent_fd) == 0) | |
+ return -1; | |
+ | |
+ fprintf(stderr, "Added keychain identities.\n"); | |
+ return 0; | |
+} | |
+ | |
+static int | |
+delete_file(int agent_fd, int keychain, const char *filename, int key_only) | |
{ | |
struct sshkey *public, *cert = NULL; | |
char *certpath = NULL, *comment = NULL; | |
int r, ret = -1; | |
+ if (keychain) | |
+ remove_from_keychain(filename); | |
+ | |
if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { | |
printf("Bad key file %s: %s\n", filename, ssh_err(r)); | |
return -1; | |
@@ -178,7 +192,7 @@ delete_all(int agent_fd) | |
} | |
static int | |
-add_file(int agent_fd, const char *filename, int key_only) | |
+add_file(int agent_fd, int keychain, const char *filename, int key_only) | |
{ | |
struct sshkey *private, *cert; | |
char *comment = NULL; | |
@@ -222,6 +236,10 @@ add_file(int agent_fd, const char *filename, int key_only) | |
filename, ssh_err(r)); | |
goto fail_load; | |
} | |
+ | |
+ if (keychain && private != NULL) | |
+ store_in_keychain(filename, ""); | |
+ | |
/* try last */ | |
if (private == NULL && pass != NULL) { | |
if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private, | |
@@ -230,6 +248,8 @@ add_file(int agent_fd, const char *filename, int key_only) | |
filename, ssh_err(r)); | |
goto fail_load; | |
} | |
+ if (keychain && private != NULL) | |
+ store_in_keychain(filename, pass); | |
} | |
if (private == NULL) { | |
/* clear passphrase since it did not work */ | |
@@ -241,8 +261,13 @@ add_file(int agent_fd, const char *filename, int key_only) | |
if (strcmp(pass, "") == 0) | |
goto fail_load; | |
if ((r = sshkey_parse_private_fileblob(keyblob, pass, | |
- &private, &comment)) == 0) | |
+ &private, &comment)) == 0) { | |
+ if (private != NULL) { | |
+ if (keychain) | |
+ store_in_keychain(filename, pass); | |
+ } | |
break; | |
+ } | |
else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { | |
fprintf(stderr, | |
"Error loading key \"%s\": %s\n", | |
@@ -440,13 +465,13 @@ lock_agent(int agent_fd, int lock) | |
} | |
static int | |
-do_file(int agent_fd, int deleting, int key_only, char *file) | |
+do_file(int agent_fd, int deleting, int keychain, int key_only, char *file) | |
{ | |
if (deleting) { | |
- if (delete_file(agent_fd, file, key_only) == -1) | |
+ if (delete_file(agent_fd, keychain, file, key_only) == -1) | |
return -1; | |
} else { | |
- if (add_file(agent_fd, file, key_only) == -1) | |
+ if (add_file(agent_fd, keychain, file, key_only) == -1) | |
return -1; | |
} | |
return 0; | |
@@ -469,6 +494,11 @@ usage(void) | |
fprintf(stderr, " -X Unlock agent.\n"); | |
fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n"); | |
fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n"); | |
+#ifdef KEYCHAIN | |
+ fprintf(stderr, " -m Add all identities stored in your Mac OS X keychain.\n"); | |
+ fprintf(stderr, " -M Store passphrases in your Mac OS X keychain.\n"); | |
+ fprintf(stderr, " With -d, remove passphrases from your Mac OS X keychain.\n"); | |
+#endif | |
} | |
int | |
@@ -480,6 +510,7 @@ main(int argc, char **argv) | |
char *pkcs11provider = NULL; | |
int r, i, ch, deleting = 0, ret = 0, key_only = 0; | |
int xflag = 0, lflag = 0, Dflag = 0; | |
+ int keychain = 0; | |
ssh_malloc_init(); /* must be called before any mallocs */ | |
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | |
@@ -507,7 +538,7 @@ main(int argc, char **argv) | |
exit(2); | |
} | |
- while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) { | |
+ while ((ch = getopt(argc, argv, "kKlLcdDxXmME:e:s:t:")) != -1) { | |
switch (ch) { | |
case 'E': | |
fingerprint_hash = ssh_digest_alg_by_name(optarg); | |
@@ -552,6 +583,13 @@ main(int argc, char **argv) | |
goto done; | |
} | |
break; | |
+ case 'm': | |
+ if (add_from_keychain(agent_fd) == -1) | |
+ ret = 1; | |
+ goto done; | |
+ case 'M': | |
+ keychain = 1; | |
+ break; | |
default: | |
usage(); | |
ret = 1; | |
@@ -600,7 +638,7 @@ main(int argc, char **argv) | |
default_files[i]); | |
if (stat(buf, &st) < 0) | |
continue; | |
- if (do_file(agent_fd, deleting, key_only, buf) == -1) | |
+ if (do_file(agent_fd, deleting, keychain, key_only, buf) == -1) | |
ret = 1; | |
else | |
count++; | |
@@ -609,7 +647,7 @@ main(int argc, char **argv) | |
ret = 1; | |
} else { | |
for (i = 0; i < argc; i++) { | |
- if (do_file(agent_fd, deleting, key_only, | |
+ if (do_file(agent_fd, deleting, keychain, key_only, | |
argv[i]) == -1) | |
ret = 1; | |
} | |
diff --git a/ssh-agent.c b/ssh-agent.c | |
index b987562..0fdc1fe 100644 | |
--- a/ssh-agent.c | |
+++ b/ssh-agent.c | |
@@ -70,6 +70,9 @@ | |
#ifdef HAVE_UTIL_H | |
# include <util.h> | |
#endif | |
+#ifdef __APPLE_LAUNCHD__ | |
+#include <launch.h> | |
+#endif | |
#include "xmalloc.h" | |
#include "ssh.h" | |
@@ -77,12 +80,15 @@ | |
#include "sshbuf.h" | |
#include "sshkey.h" | |
#include "authfd.h" | |
+#include "authfile.h" | |
#include "compat.h" | |
#include "log.h" | |
#include "misc.h" | |
#include "digest.h" | |
#include "ssherr.h" | |
#include "match.h" | |
+#include "keychain.h" | |
+#include "key.h" | |
#ifdef ENABLE_PKCS11 | |
#include "ssh-pkcs11.h" | |
@@ -863,6 +869,61 @@ send: | |
} | |
#endif /* ENABLE_PKCS11 */ | |
+static int | |
+add_identity_callback(const char *filename, const char *passphrase) | |
+{ | |
+ Key *k; | |
+ int version; | |
+ Idtab *tab; | |
+ | |
+ if ((k = key_load_private(filename, passphrase, NULL)) == NULL) | |
+ return 1; | |
+ switch (k->type) { | |
+ case KEY_RSA: | |
+ case KEY_RSA1: | |
+ if (RSA_blinding_on(k->rsa, NULL) != 1) { | |
+ key_free(k); | |
+ return 1; | |
+ } | |
+ break; | |
+ } | |
+ version = k->type == KEY_RSA1 ? 1 : 2; | |
+ tab = idtab_lookup(version); | |
+ if (lookup_identity(k, version) == NULL) { | |
+ Identity *id = xmalloc(sizeof(Identity)); | |
+ id->key = k; | |
+ id->comment = xstrdup(filename); | |
+ if (id->comment == NULL) { | |
+ key_free(k); | |
+ return 1; | |
+ } | |
+ id->death = 0; | |
+ id->confirm = 0; | |
+ TAILQ_INSERT_TAIL(&tab->idlist, id, next); | |
+ tab->nentries++; | |
+ } else { | |
+ key_free(k); | |
+ return 1; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static void | |
+process_add_from_keychain(SocketEntry *e) | |
+{ | |
+ int result; | |
+ | |
+ result = add_identities_using_keychain(&add_identity_callback); | |
+ | |
+ /* e will be NULL when ssh-agent adds keys on its own at startup */ | |
+ if (e) { | |
+ buffer_put_int(e->output, 1); | |
+ buffer_put_char(e->output, | |
+ result ? SSH_AGENT_FAILURE : SSH_AGENT_SUCCESS); | |
+ } | |
+} | |
+ | |
/* dispatch incoming messages */ | |
static void | |
@@ -957,6 +1018,9 @@ process_message(SocketEntry *e) | |
process_remove_smartcard_key(e); | |
break; | |
#endif /* ENABLE_PKCS11 */ | |
+ case SSH_AGENTC_ADD_FROM_KEYCHAIN: | |
+ process_add_from_keychain(e); | |
+ break; | |
default: | |
/* Unknown message. Respond with failure. */ | |
error("Unknown message %d", type); | |
@@ -1207,7 +1271,11 @@ usage(void) | |
int | |
main(int ac, char **av) | |
{ | |
+#ifdef __APPLE_LAUNCHD__ | |
+ int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0, l_flag = 0; | |
+#else | |
int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0; | |
+#endif | |
int sock, fd, ch, result, saved_errno; | |
u_int nalloc; | |
char *shell, *format, *pidstr, *agentsocket = NULL; | |
@@ -1240,7 +1308,11 @@ main(int ac, char **av) | |
__progname = ssh_get_progname(av[0]); | |
seed_rng(); | |
+#ifdef __APPLE_LAUNCHD__ | |
+ while ((ch = getopt(ac, av, "cDdklsE:a:P:t:")) != -1) { | |
+#else | |
while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) { | |
+#endif | |
switch (ch) { | |
case 'E': | |
fingerprint_hash = ssh_digest_alg_by_name(optarg); | |
@@ -1260,6 +1332,11 @@ main(int ac, char **av) | |
fatal("-P option already specified"); | |
pkcs11_whitelist = xstrdup(optarg); | |
break; | |
+#ifdef __APPLE_LAUNCHD__ | |
+ case 'l': | |
+ l_flag++; | |
+ break; | |
+#endif | |
case 's': | |
if (c_flag) | |
usage(); | |
@@ -1291,7 +1368,11 @@ main(int ac, char **av) | |
ac -= optind; | |
av += optind; | |
+#ifdef __APPPLE_LAUNCHD__ | |
+ if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag || l_flag)) | |
+#else | |
if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag)) | |
+#endif | |
usage(); | |
if (pkcs11_whitelist == NULL) | |
@@ -1350,6 +1431,53 @@ main(int ac, char **av) | |
* Create socket early so it will exist before command gets run from | |
* the parent. | |
*/ | |
+#ifdef __APPLE_LAUNCHD__ | |
+ if (l_flag) { | |
+ launch_data_t resp, msg, tmp; | |
+ size_t listeners_i; | |
+ | |
+ msg = launch_data_new_string(LAUNCH_KEY_CHECKIN); | |
+ | |
+ resp = launch_msg(msg); | |
+ | |
+ if (NULL == resp) { | |
+ perror("launch_msg"); | |
+ exit(1); | |
+ } | |
+ launch_data_free(msg); | |
+ switch (launch_data_get_type(resp)) { | |
+ case LAUNCH_DATA_ERRNO: | |
+ errno = launch_data_get_errno(resp); | |
+ perror("launch_msg response"); | |
+ exit(1); | |
+ case LAUNCH_DATA_DICTIONARY: | |
+ break; | |
+ default: | |
+ fprintf(stderr, "launch_msg unknown response"); | |
+ exit(1); | |
+ } | |
+ tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS); | |
+ | |
+ if (NULL == tmp) { | |
+ fprintf(stderr, "no sockets\n"); | |
+ exit(1); | |
+ } | |
+ | |
+ tmp = launch_data_dict_lookup(tmp, "Listeners"); | |
+ | |
+ if (NULL == tmp) { | |
+ fprintf(stderr, "no known listeners\n"); | |
+ exit(1); | |
+ } | |
+ | |
+ for (listeners_i = 0; listeners_i < launch_data_array_get_count(tmp); listeners_i++) { | |
+ launch_data_t obj_at_ind = launch_data_array_get_index(tmp, listeners_i); | |
+ new_socket(AUTH_SOCKET, launch_data_get_fd(obj_at_ind)); | |
+ } | |
+ | |
+ launch_data_free(resp); | |
+ } else { | |
+#endif | |
prev_mask = umask(0177); | |
sock = unix_listener(socket_name, SSH_LISTEN_BACKLOG, 0); | |
if (sock < 0) { | |
@@ -1358,6 +1486,14 @@ main(int ac, char **av) | |
cleanup_exit(1); | |
} | |
umask(prev_mask); | |
+#ifdef __APPLE_LAUNCHD__ | |
+ } | |
+#endif | |
+ | |
+#ifdef __APPLE_LAUNCHD__ | |
+ if (l_flag) | |
+ goto skip2; | |
+#endif | |
/* | |
* Fork, and have the parent execute the command, if any, or present | |
@@ -1435,6 +1571,7 @@ skip: | |
pkcs11_init(0); | |
#endif | |
new_socket(AUTH_SOCKET, sock); | |
+skip2: | |
if (ac > 0) | |
parent_alive_interval = 10; | |
idtab_init(); | |
@@ -1448,6 +1585,10 @@ skip: | |
fatal("%s: pledge: %s", __progname, strerror(errno)); | |
platform_pledge_agent(); | |
+#ifdef KEYCHAIN | |
+ process_add_from_keychain(NULL); | |
+#endif | |
+ | |
while (1) { | |
prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp); | |
result = select(max_fd + 1, readsetp, writesetp, NULL, tvp); | |
diff --git a/ssh-keysign.8 b/ssh-keysign.8 | |
index 19b0dbc..5cacf70 100644 | |
--- a/ssh-keysign.8 | |
+++ b/ssh-keysign.8 | |
@@ -72,6 +72,9 @@ accessible to others. | |
Since they are readable only by root, | |
.Nm | |
must be set-uid root if host-based authentication is used. | |
+Note that | |
+.Nm | |
+is not set-uid by default on Mac OS X. | |
.Pp | |
.It Pa /etc/ssh/ssh_host_dsa_key-cert.pub | |
.It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub | |
diff --git a/sshconnect1.c b/sshconnect1.c | |
index dc00b4c..64d192c 100644 | |
--- a/sshconnect1.c | |
+++ b/sshconnect1.c | |
@@ -51,6 +51,7 @@ | |
#include "auth.h" | |
#include "digest.h" | |
#include "ssherr.h" | |
+#include "keychain.h" | |
/* Session id for the current session. */ | |
u_char session_id[16]; | |
@@ -274,6 +275,10 @@ try_rsa_authentication(int idx) | |
snprintf(buf, sizeof(buf), | |
"Enter passphrase for RSA key '%.100s': ", comment); | |
for (i = 0; i < options.number_of_password_prompts; i++) { | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ passphrase = keychain_read_passphrase(comment, options.ask_pass_gui); | |
+ if (passphrase == NULL) | |
+#endif | |
passphrase = read_passphrase(buf, 0); | |
if (strcmp(passphrase, "") != 0) { | |
private = key_load_private_type(KEY_RSA1, | |
diff --git a/sshconnect2.c b/sshconnect2.c | |
index f8a54be..66092df 100644 | |
--- a/sshconnect2.c | |
+++ b/sshconnect2.c | |
@@ -72,6 +72,7 @@ | |
#include "hostfile.h" | |
#include "ssherr.h" | |
#include "utf8.h" | |
+#include "keychain.h" | |
#ifdef GSSAPI | |
#include "ssh-gss.h" | |
@@ -1244,6 +1245,10 @@ load_identity_file(Identity *id) | |
if (i == 0) | |
passphrase = ""; | |
else { | |
+#ifdef __APPLE_KEYCHAIN__ | |
+ passphrase = keychain_read_passphrase(id->filename, options.ask_pass_gui); | |
+ if (passphrase == NULL) | |
+#endif | |
passphrase = read_passphrase(prompt, 0); | |
if (*passphrase == '\0') { | |
debug2("no passphrase given, try next key"); | |
diff --git a/sshd.0 b/sshd.0 | |
index 6cd5f03..ceb29b7 100644 | |
--- a/sshd.0 | |
+++ b/sshd.0 | |
@@ -612,8 +612,7 @@ FILES | |
SEE ALSO | |
scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), | |
- ssh-keyscan(1), chroot(2), login.conf(5), moduli(5), sshd_config(5), | |
- inetd(8), sftp-server(8) | |
+ ssh-keyscan(1), chroot(2), sshd_config(5), sftp-server(8) | |
AUTHORS | |
OpenSSH is a derivative of the original and free ssh 1.2.12 release by | |
diff --git a/sshd.8 b/sshd.8 | |
index 7725a69..114c1d1 100644 | |
--- a/sshd.8 | |
+++ b/sshd.8 | |
@@ -929,10 +929,7 @@ The content of this file is not sensitive; it can be world-readable. | |
.Xr ssh-keygen 1 , | |
.Xr ssh-keyscan 1 , | |
.Xr chroot 2 , | |
-.Xr login.conf 5 , | |
-.Xr moduli 5 , | |
.Xr sshd_config 5 , | |
-.Xr inetd 8 , | |
.Xr sftp-server 8 | |
.Sh AUTHORS | |
OpenSSH is a derivative of the original and free | |
diff --git a/sshd.c b/sshd.c | |
index 010a2c3..12f988a 100644 | |
--- a/sshd.c | |
+++ b/sshd.c | |
@@ -2060,6 +2060,12 @@ main(int ac, char **av) | |
audit_event(SSH_AUTH_SUCCESS); | |
#endif | |
+#ifdef USE_PAM | |
+ if (options.use_pam) { | |
+ do_pam_setcred(1); | |
+ do_pam_session(); | |
+ } | |
+#endif | |
#ifdef GSSAPI | |
if (options.gss_authentication) { | |
temporarily_use_uid(authctxt->pw); | |
@@ -2067,12 +2073,6 @@ main(int ac, char **av) | |
restore_uid(); | |
} | |
#endif | |
-#ifdef USE_PAM | |
- if (options.use_pam) { | |
- do_pam_setcred(1); | |
- do_pam_session(); | |
- } | |
-#endif | |
/* | |
* In privilege separation, we fork another child and prepare | |
diff --git a/sshd_config b/sshd_config | |
index 4eb2e02..e55fe4b 100644 | |
--- a/sshd_config | |
+++ b/sshd_config | |
@@ -24,7 +24,7 @@ | |
#RekeyLimit default none | |
# Logging | |
-#SyslogFacility AUTH | |
+SyslogFacility AUTHPRIV | |
#LogLevel INFO | |
# Authentication: | |
@@ -54,8 +54,9 @@ AuthorizedKeysFile .ssh/authorized_keys | |
# Don't read the user's ~/.rhosts and ~/.shosts files | |
#IgnoreRhosts yes | |
-# To disable tunneled clear text passwords, change to no here! | |
-#PasswordAuthentication yes | |
+# To disable tunneled clear text passwords, change to no here! Also, | |
+# remember to set the UsePAM setting to 'no'. | |
+#PasswordAuthentication no | |
#PermitEmptyPasswords no | |
# Change to no to disable s/key passwords | |
@@ -80,7 +81,10 @@ AuthorizedKeysFile .ssh/authorized_keys | |
# If you just want the PAM account and session checks to run without | |
# PAM authentication, then enable this but set PasswordAuthentication | |
# and ChallengeResponseAuthentication to 'no'. | |
-#UsePAM no | |
+# Also, PAM will deny null passwords by default. If you need to allow | |
+# null passwords, add the " nullok" option to the end of the | |
+# securityserver.so line in /etc/pam.d/sshd. | |
+#UsePAM yes | |
#AllowAgentForwarding yes | |
#AllowTcpForwarding yes | |
diff --git a/sshd_config.0 b/sshd_config.0 | |
index b0160aa..757ce51 100644 | |
--- a/sshd_config.0 | |
+++ b/sshd_config.0 | |
@@ -672,7 +672,7 @@ DESCRIPTION | |
PasswordAuthentication | |
Specifies whether password authentication is allowed. The | |
- default is yes. | |
+ default is no. | |
PermitEmptyPasswords | |
When password authentication is allowed, it specifies whether the | |
@@ -902,7 +902,7 @@ DESCRIPTION | |
either PasswordAuthentication or ChallengeResponseAuthentication. | |
If UsePAM is enabled, you will not be able to run sshd(8) as a | |
- non-root user. The default is no. | |
+ non-root user. The default is yes. | |
VersionAddendum | |
Optionally specifies additional text to append to the SSH | |
diff --git a/sshd_config.5 b/sshd_config.5 | |
index ac6ccc7..e208fc8 100644 | |
--- a/sshd_config.5 | |
+++ b/sshd_config.5 | |
@@ -1136,7 +1136,7 @@ are refused if the number of unauthenticated connections reaches full (60). | |
.It Cm PasswordAuthentication | |
Specifies whether password authentication is allowed. | |
The default is | |
-.Cm yes . | |
+.Cm no . | |
.It Cm PermitEmptyPasswords | |
When password authentication is allowed, it specifies whether the | |
server allows login to accounts with empty password strings. | |
@@ -1493,7 +1493,7 @@ is enabled, you will not be able to run | |
.Xr sshd 8 | |
as a non-root user. | |
The default is | |
-.Cm no . | |
+.Cm yes . | |
.It Cm VersionAddendum | |
Optionally specifies additional text to append to the SSH protocol banner | |
sent by the server upon connection. | |
-- | |
2.12.1 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 8dea1d383891d81020225c6f83f0697c39704561 Mon Sep 17 00:00:00 2001 | |
From: Leon Klingele <[email protected]> | |
Date: Tue, 21 Mar 2017 22:38:12 +0100 | |
Subject: [PATCH 2/3] 0002-apple-sandbox-named-external.patch | |
--- | |
sshd.c | 7 +++++++ | |
1 file changed, 7 insertions(+) | |
diff --git a/sshd.c b/sshd.c | |
index 12f988a..088fa4d 100644 | |
--- a/sshd.c | |
+++ b/sshd.c | |
@@ -619,10 +619,17 @@ privsep_preauth(Authctxt *authctxt) | |
/* Arrange for logging to be sent to the monitor */ | |
set_log_handler(mm_log_handler, pmonitor); | |
+#ifdef __APPLE_SANDBOX_NAMED_EXTERNAL__ | |
+ /* We need to do this before we chroot() so we can read sshd.sb */ | |
+ if (box != NULL) | |
+ ssh_sandbox_child(box); | |
+#endif | |
privsep_preauth_child(); | |
setproctitle("%s", "[net]"); | |
+#ifndef __APPLE_SANDBOX_NAMED_EXTERNAL__ | |
if (box != NULL) | |
ssh_sandbox_child(box); | |
+#endif | |
return 0; | |
} | |
-- | |
2.12.1 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From fc0bde10e9f3bb27b4cb3c28038f8cdad95fea23 Mon Sep 17 00:00:00 2001 | |
From: Leon Klingele <[email protected]> | |
Date: Tue, 21 Mar 2017 22:38:50 +0100 | |
Subject: [PATCH 3/3] 0003-launchd.patch | |
--- | |
clientloop.c | 36 ++++++++++++++++++++++++++++++++++++ | |
1 file changed, 36 insertions(+) | |
diff --git a/clientloop.c b/clientloop.c | |
index 0648162..e208c8d 100644 | |
--- a/clientloop.c | |
+++ b/clientloop.c | |
@@ -315,6 +315,11 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |
struct stat st; | |
u_int now, x11_timeout_real; | |
+#if __APPLE__ | |
+ // TODO(leon): Combine with channels.c's is_path_to_xsocket | |
+ int is_path_to_socket = 0; | |
+#endif /* __APPLE__ */ | |
+ | |
*_proto = proto; | |
*_data = data; | |
proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0'; | |
@@ -331,6 +336,34 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |
} | |
if (xauth_path != NULL) { | |
+#if __APPLE__ | |
+ { | |
+ /* | |
+ * If using launchd socket, remove the screen number from the end | |
+ * of $DISPLAY. is_path_to_socket is used later in this function | |
+ * to determine if an error should be displayed. | |
+ */ | |
+ char path[PATH_MAX]; | |
+ struct stat sbuf; | |
+ | |
+ strlcpy(path, display, sizeof(path)); | |
+ if (0 == stat(path, &sbuf)) { | |
+ is_path_to_socket = 1; | |
+ } else { | |
+ char *dot = strrchr(path, '.'); | |
+ if (dot) { | |
+ *dot = '\0'; | |
+ /* screen = atoi(dot + 1); */ | |
+ if (0 == stat(path, &sbuf)) { | |
+ is_path_to_socket = 1; | |
+ debug("x11_get_proto: $DISPLAY is launchd, removing screennum"); | |
+ setenv("DISPLAY", path, 1); | |
+ } | |
+ } | |
+ } | |
+ } | |
+#endif /* __APPLE__ */ | |
+ | |
/* | |
* Handle FamilyLocal case where $DISPLAY does | |
* not match an authorization entry. For this we | |
@@ -441,6 +474,9 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |
u_int8_t rnd[16]; | |
u_int i; | |
+#if __APPLE__ | |
+ if (!is_path_to_socket) | |
+#endif /* __APPLE__ */ | |
logit("Warning: No xauth data; " | |
"using fake authentication data for X11 forwarding."); | |
strlcpy(proto, SSH_X11_PROTO, sizeof proto); | |
-- | |
2.12.1 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
a |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment