Ticket #27250: 0002-Apple-keychain-integration-other-changes.patch

File 0002-Apple-keychain-integration-other-changes.patch, 64.0 KB (added by lassi.tuura@…, 13 years ago)

Patch regenerated in more clean format with git

  • Makefile.in

    From 94e42cad73ce6c03abb842a905824586313eabc6 Mon Sep 17 00:00:00 2001
    From: Lassi Tuura <lat@cern.ch>
    Date: Wed, 21 Sep 2011 19:35:54 +0200
    Subject: [PATCH 2/2] Apple keychain integration + other changes.
    
    ---
     Makefile.in   |   18 +-
     audit-bsm.c   |    7 +-
     auth-pam.c    |    5 +-
     auth.c        |    2 +-
     authfd.c      |   23 ++
     authfd.h      |    3 +
     config.h.in   |   12 +
     configure.ac  |   30 +++
     groupaccess.c |   59 +++++-
     groupaccess.h |    2 +-
     keychain.c    |  694 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     keychain.h    |   45 ++++
     readconf.c    |   20 ++-
     readconf.h    |    4 +
     scp.1         |    4 +-
     scp.c         |  148 ++++++++++++
     servconf.c    |    6 +-
     session.c     |    4 +
     ssh-add.0     |   11 +-
     ssh-add.1     |    8 +-
     ssh-add.c     |   61 ++++-
     ssh-agent.c   |  140 ++++++++++++
     ssh-keysign.8 |    3 +
     sshconnect1.c |    5 +
     sshconnect2.c |    5 +
     sshd.0        |    4 +-
     sshd.8        |    3 -
     sshd.c        |   12 +-
     sshd_config   |   12 +-
     sshd_config.0 |    4 +-
     sshd_config.5 |    4 +-
     31 files changed, 1301 insertions(+), 57 deletions(-)
     create mode 100644 keychain.c
     create mode 100644 keychain.h
    
    diff --git a/Makefile.in b/Makefile.in
    index e479a44..65538db 100644
    a b SED=@SED@ 
    5656ENT=@ENT@
    5757XAUTH_PATH=@XAUTH_PATH@
    5858LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
     59KEYCHAIN_LDFLAGS=@KEYCHAIN_LDFLAGS@
    5960EXEEXT=@EXEEXT@
    6061MANFMT=@MANFMT@
    6162
    SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ 
    9394        roaming_common.o roaming_serv.o \
    9495        sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o
    9596
     97KEYCHAINOBJS=keychain.o
     98
    9699MANPAGES        = 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
    97100MANPAGES_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
    98101MANTYPE         = @MANTYPE@
    all: $(CONFIGFILES) $(MANPAGES) $(TARGETS) 
    125128$(LIBSSH_OBJS): Makefile.in config.h
    126129$(SSHOBJS): Makefile.in config.h
    127130$(SSHDOBJS): Makefile.in config.h
     131$(KEYCHAINOBJS): Makefile.in config.h
    128132
    129133.c.o:
    130134        $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
    libssh.a: $(LIBSSH_OBJS) 
    138142        $(AR) rv $@ $(LIBSSH_OBJS)
    139143        $(RANLIB) $@
    140144
    141 ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
    142         $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS)
     145ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) $(KEYCHAINOBJS)
     146        $(LD) -o $@ $(SSHOBJS) $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS)
    143147
    144148sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS)
    145149        $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS)
    sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) 
    147151scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o
    148152        $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
    149153
    150 ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o
    151         $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
     154ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o $(KEYCHAINOBJS)
     155        $(LD) -o $@ ssh-add.o $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
    152156
    153 ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o
    154         $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
     157ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o $(KEYCHAINOBJS)
     158        $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
    155159
    156160ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
    157161        $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
    install-files: 
    255259        $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
    256260        $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
    257261        $(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
    258         $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
     262        $(INSTALL) -m 0711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
    259263        $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
    260264        $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
    261265        $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
  • audit-bsm.c

    diff --git a/audit-bsm.c b/audit-bsm.c
    index f196d4f..2899ef5 100644
    a b bsm_audit_record(int typ, char *string, au_event_t event_no) 
    194194        pid_t           pid = getpid();
    195195        AuditInfoTermID tid = ssh_bsm_tid;
    196196
    197         if (the_authctxt != NULL && the_authctxt->valid) {
     197        if (the_authctxt == NULL) {
     198                error("BSM audit: audit record internal error (NULL ctxt)");
     199                abort();
     200        }
     201       
     202        if (the_authctxt->valid) {
    198203                uid = the_authctxt->pw->pw_uid;
    199204                gid = the_authctxt->pw->pw_gid;
    200205        }
  • auth-pam.c

    diff --git a/auth-pam.c b/auth-pam.c
    index 675006e..a195899 100644
    a b sshpam_query(void *ctx, char **name, char **info, 
    793793                                xfree(msg);
    794794                                return (0);
    795795                        }
    796                         error("PAM: %s for %s%.100s from %.100s", msg,
     796                        error("PAM: %s for %s%.100s from %.100s via %s", msg,
    797797                            sshpam_authctxt->valid ? "" : "illegal user ",
    798798                            sshpam_authctxt->user,
    799                             get_remote_name_or_ip(utmp_len, options.use_dns));
     799                            get_remote_name_or_ip(utmp_len, options.use_dns),
     800                            get_local_ipaddr(packet_get_connection_in()));
    800801                        /* FALLTHROUGH */
    801802                default:
    802803                        *num = 0;
  • auth.c

    diff --git a/auth.c b/auth.c
    index cd95da9..94fa21f 100644
    a b allowed_user(struct passwd * pw) 
    209209        }
    210210        if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
    211211                /* Get the user's group access list (primary and supplementary) */
    212                 if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
     212                if (ga_init(pw) == 0) {
    213213                        logit("User %.100s from %.100s not allowed because "
    214214                            "not in any group", pw->pw_name, hostname);
    215215                        return 0;
  • authfd.c

    diff --git a/authfd.c b/authfd.c
    index f037e83..c25b157 100644
    a b ssh_remove_all_identities(AuthenticationConnection *auth, int version) 
    689689        return decode_reply(type);
    690690}
    691691
     692/*
     693 * Adds identities using passphrases stored in the keychain.  This call is not
     694 * meant to be used by normal applications.
     695 */
     696
     697int
     698ssh_add_from_keychain(AuthenticationConnection *auth)
     699{
     700        Buffer msg;
     701        int type;
     702
     703        buffer_init(&msg);
     704        buffer_put_char(&msg, SSH_AGENTC_ADD_FROM_KEYCHAIN);
     705
     706        if (ssh_request_reply(auth, &msg, &msg) == 0) {
     707                buffer_free(&msg);
     708                return 0;
     709        }
     710        type = buffer_get_char(&msg);
     711        buffer_free(&msg);
     712        return decode_reply(type);
     713}
     714
    692715int
    693716decode_reply(int type)
    694717{
  • authfd.h

    diff --git a/authfd.h b/authfd.h
    index 2582a27..7b786fe 100644
    a b  
    4949#define SSH2_AGENTC_ADD_ID_CONSTRAINED          25
    5050#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
    5151
     52/* keychain */
     53#define SSH_AGENTC_ADD_FROM_KEYCHAIN            27
     54
    5255#define SSH_AGENT_CONSTRAIN_LIFETIME            1
    5356#define SSH_AGENT_CONSTRAIN_CONFIRM             2
    5457
  • config.h.in

    diff --git a/config.h.in b/config.h.in
    index baf0011..431720a 100644
    a b  
    7171/* Define if your snprintf is busted */
    7272#undef BROKEN_SNPRINTF
    7373
     74/* platform uses an in-memory credentials cache */
     75#undef USE_CCAPI
     76
     77/* platform has a Security Authorization Session API */
     78#undef USE_SECURITY_SESSION_API
     79
     80/* Define to 1 if you have the `copyfile' function. */
     81#undef HAVE_COPYFILE
     82
     83/* Define to 1 if you have the <copyfile.h> header file. */
     84#undef HAVE_COPYFILE_H
     85
    7486/* tcgetattr with ICANON may hang */
    7587#undef BROKEN_TCGETATTR_ICANON
    7688
  • configure.ac

    diff --git a/configure.ac b/configure.ac
    index 8cc7ce9..bd8fdaa 100644
    a b if test ! -z "$blibpath" ; then 
    41974197        AC_MSG_WARN([Please check and edit blibpath in LDFLAGS in Makefile])
    41984198fi
    41994199
     4200dnl Keychain support
     4201AC_ARG_WITH(keychain,
     4202        [  --with-keychain=apple   Use Mac OS X Keychain],
     4203        [
     4204                case "$withval" in
     4205                apple|no)
     4206                        KEYCHAIN=$withval
     4207                        ;;
     4208                *)
     4209                        AC_MSG_ERROR(invalid keychain type: $withval)
     4210                        ;;
     4211                esac
     4212        ]
     4213)
     4214if test ! -z "$KEYCHAIN" -a "$KEYCHAIN" != "no"; then
     4215        case "$KEYCHAIN" in
     4216        apple)
     4217                AC_CHECK_HEADERS(Security/Security.h, [
     4218                                CPPFLAGS="$CPPFLAGS -D__APPLE_KEYCHAIN__"
     4219                                KEYCHAIN_LDFLAGS="-framework Security -framework CoreFoundation"
     4220                                AC_SUBST(KEYCHAIN_LDFLAGS)
     4221                                ],
     4222                                AC_MSG_WARN([Security framework not found. Disabling Mac OS X Keychain support.]))
     4223                ;;
     4224        esac
     4225fi
     4226
    42004227dnl Adding -Werror to CFLAGS early prevents configure tests from running.
    42014228dnl Add now.
    42024229CFLAGS="$CFLAGS $werror_flags"
    42034230
     4231AC_CHECK_FUNCS(copyfile)
     4232AC_CHECK_HEADERS(copyfile.h)
     4233
    42044234if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
    42054235        TEST_SSH_IPV6=no
    42064236else
  • groupaccess.c

    diff --git a/groupaccess.c b/groupaccess.c
    index 2381aeb..2b5c600 100644
    a b  
    3333#include <stdarg.h>
    3434#include <string.h>
    3535
     36#ifdef __APPLE_MEMBERSHIP__
     37#include <membership.h>
     38#endif
     39
    3640#include "xmalloc.h"
    3741#include "groupaccess.h"
    3842#include "match.h"
    3943#include "log.h"
    4044
     45#ifdef __APPLE_MEMBERSHIP__
     46// SPI for 5235093
     47int32_t getgrouplist_2(const char *, gid_t, gid_t **);
     48int32_t getgroupcount(const char *, gid_t);
     49#endif
     50
    4151static int ngroups;
    4252static char **groups_byname;
     53#ifdef __APPLE_MEMBERSHIP__
     54uuid_t u_uuid;
     55#endif
    4356
    4457/*
    4558 * Initialize group access list for user with primary (base) and
    4659 * supplementary groups.  Return the number of groups in the list.
    4760 */
    4861int
    49 ga_init(const char *user, gid_t base)
     62ga_init(struct passwd *pw)
    5063{
    51         gid_t *groups_bygid;
     64        gid_t *groups_bygid = NULL;
    5265        int i, j;
    5366        struct group *gr;
    5467
     68#ifdef __APPLE_MEMBERSHIP__
     69        if (0 != mbr_uid_to_uuid(pw->pw_uid, u_uuid))
     70                return 0;
     71#endif
     72
    5573        if (ngroups > 0)
    5674                ga_free();
    5775
     76#ifndef __APPLE_MEMBERSHIP__
    5877        ngroups = NGROUPS_MAX;
    5978#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
    6079        ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX));
    61 #endif
    62 
     80#endif 
    6381        groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid));
     82#else
     83        if (-1 == (ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid,
     84            &groups_bygid))) {
     85                logit("getgrouplist_2 failed");
     86                return;
     87        }
     88#endif
    6489        groups_byname = xcalloc(ngroups, sizeof(*groups_byname));
    65 
    66         if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
    67                 logit("getgrouplist: groups list too small");
     90#ifndef __APPLE_MEMBERSHIP__
     91        if (getgrouplist(pw->pw_name, pw->pw_gid, groups_bygid, &ngroups) == -1) {
     92            logit("getgrouplist: groups list too small");
     93                xfree(groups_bygid);
     94                return;
     95        }
     96#endif
    6897        for (i = 0, j = 0; i < ngroups; i++)
    6998                if ((gr = getgrgid(groups_bygid[i])) != NULL)
    7099                        groups_byname[j++] = xstrdup(gr->gr_name);
    ga_init(const char *user, gid_t base) 
    75104/*
    76105 * Return 1 if one of user's groups is contained in groups.
    77106 * Return 0 otherwise.  Use match_pattern() for string comparison.
     107 * Use mbr_check_membership() for membership checking on Mac OS X.
    78108 */
    79109int
    80110ga_match(char * const *groups, int n)
    81111{
     112#ifdef __APPLE_MEMBERSHIP__
     113        int i, ismember = 0;
     114        uuid_t g_uuid;
     115        struct group *grp;
     116
     117        for (i = 0; i < n; i++) {
     118                if ((grp = getgrnam(groups[i])) == NULL ||
     119                   (mbr_gid_to_uuid(grp->gr_gid, g_uuid) != 0) ||
     120                   (mbr_check_membership(u_uuid, g_uuid, &ismember) != 0))
     121                        return 0;
     122                if (ismember)
     123                        return 1;
     124        }
     125#else
    82126        int i, j;
    83127
    84128        for (i = 0; i < ngroups; i++)
    85129                for (j = 0; j < n; j++)
    86130                        if (match_pattern(groups_byname[i], groups[j]))
    87131                                return 1;
     132#endif
    88133        return 0;
    89134}
    90135
  • groupaccess.h

    diff --git a/groupaccess.h b/groupaccess.h
    index 000578e..ddea117 100644
    a b  
    2727#ifndef GROUPACCESS_H
    2828#define GROUPACCESS_H
    2929
    30 int      ga_init(const char *, gid_t);
     30int      ga_init(struct passwd *);
    3131int      ga_match(char * const *, int);
    3232int      ga_match_pattern_list(const char *);
    3333void     ga_free(void);
  • new file keychain.c

    diff --git a/keychain.c b/keychain.c
    new file mode 100644
    index 0000000..a6d5855
    - +  
     1/*
     2 * Copyright (c) 2007 Apple Inc. All rights reserved.
     3 *
     4 * @APPLE_BSD_LICENSE_HEADER_START@
     5 *
     6 * Redistribution and use in source and binary forms, with or without
     7 * modification, are permitted provided that the following conditions
     8 * are met:
     9 *
     10 * 1.  Redistributions of source code must retain the above copyright
     11 *     notice, this list of conditions and the following disclaimer.
     12 * 2.  Redistributions in binary form must reproduce the above copyright
     13 *     notice, this list of conditions and the following disclaimer in the
     14 *     documentation and/or other materials provided with the distribution.
     15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
     16 *     contributors may be used to endorse or promote products derived from
     17 *     this software without specific prior written permission.
     18 *
     19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 *
     30 * @APPLE_BSD_LICENSE_HEADER_END@
     31 */
     32
     33#include "includes.h"
     34
     35#include <stdio.h>
     36#include <string.h>
     37
     38#include "xmalloc.h"
     39#include "key.h"
     40#include "authfd.h"
     41#include "authfile.h"
     42
     43#if defined(__APPLE_KEYCHAIN__)
     44
     45#include <CoreFoundation/CoreFoundation.h>
     46#include <Security/Security.h>
     47
     48/* Our Security/SecPassword.h is not yet API, so I will define the constants that I am using here. */
     49int kSecPasswordGet     = 1<<0;  // Get password from keychain or user
     50int kSecPasswordSet     = 1<<1;  // Set password (passed in if kSecPasswordGet not set, otherwise from user)
     51int kSecPasswordFail    = 1<<2;  // Wrong password (ignore item in keychain and flag error)
     52OSStatus SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef);
     53OSStatus SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data);
     54OSStatus SecPasswordSetInitialAccess(SecPasswordRef itemRef, SecAccessRef accessRef);
     55
     56#endif
     57
     58/*
     59 * Platform-specific helper functions.
     60 */
     61
     62#if defined(__APPLE_KEYCHAIN__)
     63
     64static int get_boolean_preference(const char *key, int default_value,
     65    int foreground)
     66{
     67        int value = default_value;
     68        CFStringRef keyRef = NULL;
     69        CFPropertyListRef valueRef = NULL;
     70
     71        keyRef = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
     72        if (keyRef != NULL)
     73                valueRef = CFPreferencesCopyAppValue(keyRef,
     74                    CFSTR("org.openbsd.openssh"));
     75        if (valueRef != NULL)
     76                if (CFGetTypeID(valueRef) == CFBooleanGetTypeID())
     77                        value = CFBooleanGetValue(valueRef);
     78                else if (foreground)
     79                        fprintf(stderr, "Ignoring nonboolean %s preference.\n", key);
     80
     81        if (keyRef)
     82                CFRelease(keyRef);
     83        if (valueRef)
     84                CFRelease(valueRef);
     85
     86        return value;
     87}
     88
     89#endif
     90
     91/*
     92 * Store the passphrase for a given identity in the keychain.
     93 */
     94void
     95store_in_keychain(const char *filename, const char *passphrase)
     96{
     97
     98#if defined(__APPLE_KEYCHAIN__)
     99
     100        /*
     101         * store_in_keychain
     102         * Mac OS X implementation
     103         */
     104
     105        CFStringRef cfstr_relative_filename = NULL;
     106        CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL;
     107        CFStringRef cfstr_filename = NULL;
     108        CFDataRef cfdata_filename = NULL;
     109        CFIndex filename_len;
     110        UInt8 *label = NULL;
     111        UInt8 *utf8_filename;
     112        OSStatus rv;
     113        SecKeychainItemRef itemRef = NULL;
     114        SecTrustedApplicationRef apps[] = {NULL, NULL, NULL};
     115        CFArrayRef trustedlist = NULL;
     116        SecAccessRef initialAccess = NULL;
     117
     118        /* Bail out if KeychainIntegration preference is -bool NO */
     119        if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) {
     120                fprintf(stderr, "Keychain integration is disabled.\n");
     121                goto err;
     122        }
     123
     124        /* Interpret filename with the correct encoding. */
     125        if ((cfstr_relative_filename =
     126            CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL)
     127            {
     128                fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n");
     129                goto err;
     130        }
     131        if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL,
     132            cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) {
     133                fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n");
     134                goto err;
     135        }
     136        if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) ==
     137            NULL) {
     138                fprintf(stderr, "CFURLCopyAbsoluteURL failed\n");
     139                goto err;
     140        }
     141        if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename,
     142            kCFURLPOSIXPathStyle)) == NULL) {
     143                fprintf(stderr, "CFURLCopyFileSystemPath failed\n");
     144                goto err;
     145        }
     146        if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL,
     147            cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) {
     148                fprintf(stderr, "CFStringCreateExternalRepresentation failed\n");
     149                goto err;
     150        }
     151        filename_len = CFDataGetLength(cfdata_filename);
     152        if ((label = xmalloc(filename_len + 5)) == NULL) {
     153                fprintf(stderr, "xmalloc failed\n");
     154                goto err;
     155        }
     156        memcpy(label, "SSH: ", 5);
     157        utf8_filename = label + 5;
     158        CFDataGetBytes(cfdata_filename, CFRangeMake(0, filename_len),
     159            utf8_filename);
     160
     161        /* Check if we already have this passphrase. */
     162        rv = SecKeychainFindGenericPassword(NULL, 3, "SSH", filename_len,
     163            (char *)utf8_filename, NULL, NULL, &itemRef);
     164        if (rv == errSecItemNotFound) {
     165                /* Add a new keychain item. */
     166                SecKeychainAttribute attrs[] = {
     167                        {kSecLabelItemAttr, filename_len + 5, label},
     168                        {kSecServiceItemAttr, 3, "SSH"},
     169                        {kSecAccountItemAttr, filename_len, utf8_filename}
     170                };
     171                SecKeychainAttributeList attrList =
     172                    {sizeof(attrs) / sizeof(attrs[0]), attrs};
     173                if (SecTrustedApplicationCreateFromPath("/usr/bin/ssh-agent",
     174                    &apps[0]) != noErr ||
     175                    SecTrustedApplicationCreateFromPath("/usr/bin/ssh-add",
     176                    &apps[1]) != noErr ||
     177                    SecTrustedApplicationCreateFromPath("/usr/bin/ssh",
     178                    &apps[2]) != noErr) {
     179                        fprintf(stderr, "SecTrustedApplicationCreateFromPath failed\n");
     180                        goto err;
     181                }
     182                if ((trustedlist = CFArrayCreate(NULL, (const void **)apps,
     183                    sizeof(apps) / sizeof(apps[0]), &kCFTypeArrayCallBacks)) ==
     184                    NULL) {
     185                        fprintf(stderr, "CFArrayCreate failed\n");
     186                        goto err;
     187                }
     188                if (SecAccessCreate(cfstr_filename, trustedlist,
     189                    &initialAccess) != noErr) {
     190                        fprintf(stderr, "SecAccessCreate failed\n");
     191                        goto err;
     192                }
     193                if (SecKeychainItemCreateFromContent(
     194                    kSecGenericPasswordItemClass, &attrList, strlen(passphrase),
     195                    passphrase, NULL, initialAccess, NULL) == noErr)
     196                        fprintf(stderr, "Passphrase stored in keychain: %s\n", filename);
     197                else
     198                        fprintf(stderr, "Could not create keychain item\n");
     199        } else if (rv == noErr) {
     200                /* Update an existing keychain item. */
     201                if (SecKeychainItemModifyAttributesAndData(itemRef, NULL,
     202                    strlen(passphrase), passphrase) == noErr)
     203                        fprintf(stderr, "Passphrase updated in keychain: %s\n", filename);
     204                else
     205                        fprintf(stderr, "Could not modify keychain item\n");
     206        } else
     207                fprintf(stderr, "Could not access keychain\n");
     208
     209err:    /* Clean up. */
     210        if (cfstr_relative_filename)
     211                CFRelease(cfstr_relative_filename);
     212        if (cfurl_relative_filename)
     213                CFRelease(cfurl_relative_filename);
     214        if (cfurl_filename)
     215                CFRelease(cfurl_filename);
     216        if (cfstr_filename)
     217                CFRelease(cfstr_filename);
     218        if (cfdata_filename)
     219                CFRelease(cfdata_filename);
     220        if (label)
     221                xfree(label);
     222        if (itemRef)
     223                CFRelease(itemRef);
     224        if (apps[0])
     225                CFRelease(apps[0]);
     226        if (apps[1])
     227                CFRelease(apps[1]);
     228        if (apps[2])
     229                CFRelease(apps[2]);
     230        if (trustedlist)
     231                CFRelease(trustedlist);
     232        if (initialAccess)
     233                CFRelease(initialAccess);
     234
     235#else
     236
     237        /*
     238         * store_in_keychain
     239         * no keychain implementation
     240         */
     241
     242        fprintf(stderr, "Keychain is not available on this system\n");
     243
     244#endif
     245
     246}
     247
     248/*
     249 * Remove the passphrase for a given identity from the keychain.
     250 */
     251void
     252remove_from_keychain(const char *filename)
     253{
     254
     255#if defined(__APPLE_KEYCHAIN__)
     256
     257        /*
     258         * remove_from_keychain
     259         * Mac OS X implementation
     260         */
     261
     262        CFStringRef cfstr_relative_filename = NULL;
     263        CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL;
     264        CFStringRef cfstr_filename = NULL;
     265        CFDataRef cfdata_filename = NULL;
     266        CFIndex filename_len;
     267        const UInt8 *utf8_filename;
     268        OSStatus rv;
     269        SecKeychainItemRef itemRef = NULL;
     270
     271        /* Bail out if KeychainIntegration preference is -bool NO */
     272        if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) {
     273                fprintf(stderr, "Keychain integration is disabled.\n");
     274                goto err;
     275        }
     276
     277        /* Interpret filename with the correct encoding. */
     278        if ((cfstr_relative_filename =
     279            CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL)
     280            {
     281                fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n");
     282                goto err;
     283        }
     284        if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL,
     285            cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) {
     286                fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n");
     287                goto err;
     288        }
     289        if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) ==
     290            NULL) {
     291                fprintf(stderr, "CFURLCopyAbsoluteURL failed\n");
     292                goto err;
     293        }
     294        if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename,
     295            kCFURLPOSIXPathStyle)) == NULL) {
     296                fprintf(stderr, "CFURLCopyFileSystemPath failed\n");
     297                goto err;
     298        }
     299        if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL,
     300            cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) {
     301                fprintf(stderr, "CFStringCreateExternalRepresentation failed\n");
     302                goto err;
     303        }
     304        filename_len = CFDataGetLength(cfdata_filename);
     305        utf8_filename = CFDataGetBytePtr(cfdata_filename);
     306
     307        /* Check if we already have this passphrase. */
     308        rv = SecKeychainFindGenericPassword(NULL, 3, "SSH", filename_len,
     309            (const char *)utf8_filename, NULL, NULL, &itemRef);
     310        if (rv == noErr) {
     311                /* Remove the passphrase from the keychain. */
     312                if (SecKeychainItemDelete(itemRef) == noErr)
     313                        fprintf(stderr, "Passphrase removed from keychain: %s\n", filename);
     314                else
     315                        fprintf(stderr, "Could not remove keychain item\n");
     316        } else if (rv != errSecItemNotFound)
     317                fprintf(stderr, "Could not access keychain\n");
     318
     319err:    /* Clean up. */
     320        if (cfstr_relative_filename)
     321                CFRelease(cfstr_relative_filename);
     322        if (cfurl_relative_filename)
     323                CFRelease(cfurl_relative_filename);
     324        if (cfurl_filename)
     325                CFRelease(cfurl_filename);
     326        if (cfstr_filename)
     327                CFRelease(cfstr_filename);
     328        if (cfdata_filename)
     329                CFRelease(cfdata_filename);
     330        if (itemRef)
     331                CFRelease(itemRef);
     332
     333#else
     334
     335        /*
     336         * remove_from_keychain
     337         * no keychain implementation
     338         */
     339
     340        fprintf(stderr, "Keychain is not available on this system\n");
     341
     342#endif
     343
     344}
     345
     346/*
     347 * Add identities to ssh-agent using passphrases stored in the keychain.
     348 * Returns zero on success and nonzero on failure.
     349 * add_identity is a callback into ssh-agent.  It takes a filename and a
     350 * passphrase, and attempts to add the identity to the agent.  It returns
     351 * zero on success and nonzero on failure.
     352 */
     353int
     354add_identities_using_keychain(int (*add_identity)(const char *, const char *))
     355{
     356
     357#if defined(__APPLE_KEYCHAIN__)
     358
     359        /*
     360         * add_identities_using_keychain
     361         * Mac OS X implementation
     362         */
     363
     364        OSStatus rv;
     365        SecKeychainSearchRef searchRef;
     366        SecKeychainItemRef itemRef;
     367        UInt32 length;
     368        void *data;
     369        CFIndex maxsize;
     370
     371        /* Bail out if KeychainIntegration preference is -bool NO */
     372        if (get_boolean_preference("KeychainIntegration", 1, 0) == 0)
     373                return 0;
     374
     375        /* Search for SSH passphrases in the keychain */
     376        SecKeychainAttribute attrs[] = {
     377                {kSecServiceItemAttr, 3, "SSH"}
     378        };
     379        SecKeychainAttributeList attrList =
     380            {sizeof(attrs) / sizeof(attrs[0]), attrs};
     381        if ((rv = SecKeychainSearchCreateFromAttributes(NULL,
     382            kSecGenericPasswordItemClass, &attrList, &searchRef)) != noErr)
     383                return 0;
     384
     385        /* Iterate through the search results. */
     386        while ((rv = SecKeychainSearchCopyNext(searchRef, &itemRef)) == noErr) {
     387                UInt32 tag = kSecAccountItemAttr;
     388                UInt32 format = kSecFormatUnknown;
     389                SecKeychainAttributeInfo info = {1, &tag, &format};
     390                SecKeychainAttributeList *itemAttrList = NULL;
     391                CFStringRef cfstr_filename = NULL;
     392                char *filename = NULL;
     393                char *passphrase = NULL;
     394
     395                /* Retrieve filename and passphrase. */
     396                if ((rv = SecKeychainItemCopyAttributesAndData(itemRef, &info,
     397                    NULL, &itemAttrList, &length, &data)) != noErr)
     398                        goto err;
     399                if (itemAttrList->count != 1)
     400                        goto err;
     401                cfstr_filename = CFStringCreateWithBytes(NULL,
     402                    itemAttrList->attr->data, itemAttrList->attr->length,
     403                    kCFStringEncodingUTF8, true);
     404                maxsize = CFStringGetMaximumSizeOfFileSystemRepresentation(
     405                    cfstr_filename);
     406                if ((filename = xmalloc(maxsize)) == NULL)
     407                        goto err;
     408                if (CFStringGetFileSystemRepresentation(cfstr_filename,
     409                    filename, maxsize) == false)
     410                        goto err;
     411                if ((passphrase = xmalloc(length + 1)) == NULL)
     412                        goto err;
     413                memcpy(passphrase, data, length);
     414                passphrase[length] = '\0';
     415
     416                /* Add the identity. */
     417                add_identity(filename, passphrase);
     418
     419err:            /* Clean up. */
     420                if (itemRef)
     421                        CFRelease(itemRef);
     422                if (cfstr_filename)
     423                        CFRelease(cfstr_filename);
     424                if (filename)
     425                        xfree(filename);
     426                if (passphrase)
     427                        xfree(passphrase);
     428                if (itemAttrList)
     429                        SecKeychainItemFreeAttributesAndData(itemAttrList,
     430                            data);
     431        }
     432
     433        CFRelease(searchRef);
     434
     435        return 0;
     436
     437#else
     438
     439        /*
     440         * add_identities_using_keychain
     441         * no implementation
     442         */
     443
     444        return 1;
     445
     446#endif
     447
     448}
     449
     450/*
     451 * Prompt the user for a key's passphrase.  The user will be offered the option
     452 * of storing the passphrase in their keychain.  Returns the passphrase
     453 * (which the caller is responsible for xfreeing), or NULL if this function
     454 * fails or is not implemented.  If this function is not implemented, ssh will
     455 * fall back on the standard read_passphrase function, and the user will need
     456 * to use ssh-add -K to add their keys to the keychain.
     457 */
     458char *
     459keychain_read_passphrase(const char *filename, int oAskPassGUI)
     460{
     461
     462#if defined(__APPLE_KEYCHAIN__)
     463
     464        /*
     465         * keychain_read_passphrase
     466         * Mac OS X implementation
     467         */
     468
     469        CFStringRef cfstr_relative_filename = NULL;
     470        CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL;
     471        CFStringRef cfstr_filename = NULL;
     472        CFDataRef cfdata_filename = NULL;
     473        CFIndex filename_len;
     474        UInt8 *label = NULL;
     475        UInt8 *utf8_filename;
     476        SecPasswordRef passRef = NULL;
     477        SecTrustedApplicationRef apps[] = {NULL, NULL, NULL};
     478        CFArrayRef trustedlist = NULL;
     479        SecAccessRef initialAccess = NULL;
     480        CFURLRef path = NULL;
     481        CFStringRef pathFinal = NULL;
     482        CFURLRef bundle_url = NULL;
     483        CFBundleRef bundle = NULL;
     484        CFStringRef promptTemplate = NULL, prompt = NULL;
     485        UInt32 length;
     486        const void *data;
     487        AuthenticationConnection *ac = NULL;
     488        char *result = NULL;
     489
     490        /* Bail out if KeychainIntegration preference is -bool NO */
     491        if (get_boolean_preference("KeychainIntegration", 1, 1) == 0)
     492                goto err;
     493
     494        /* Bail out if the user set AskPassGUI preference to -bool NO */
     495        if (get_boolean_preference("AskPassGUI", 1, 1) == 0 || oAskPassGUI == 0)
     496                goto err;
     497
     498        /* Bail out if we can't communicate with ssh-agent */
     499        if ((ac = ssh_get_authentication_connection()) == NULL)
     500                goto err;
     501
     502        /* Interpret filename with the correct encoding. */
     503        if ((cfstr_relative_filename =
     504            CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL)
     505            {
     506                fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n");
     507                goto err;
     508        }
     509        if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL,
     510            cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) {
     511                fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n");
     512                goto err;
     513        }
     514        if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) ==
     515            NULL) {
     516                fprintf(stderr, "CFURLCopyAbsoluteURL failed\n");
     517                goto err;
     518        }
     519        if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename,
     520            kCFURLPOSIXPathStyle)) == NULL) {
     521                fprintf(stderr, "CFURLCopyFileSystemPath failed\n");
     522                goto err;
     523        }
     524        if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL,
     525            cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) {
     526                fprintf(stderr, "CFStringCreateExternalRepresentation failed\n");
     527                goto err;
     528        }
     529        filename_len = CFDataGetLength(cfdata_filename);
     530        if ((label = xmalloc(filename_len + 5)) == NULL) {
     531                fprintf(stderr, "xmalloc failed\n");
     532                goto err;
     533        }
     534        memcpy(label, "SSH: ", 5);
     535        utf8_filename = label + 5;
     536        CFDataGetBytes(cfdata_filename, CFRangeMake(0, filename_len),
     537            utf8_filename);
     538
     539        /* Build a SecPasswordRef. */
     540        SecKeychainAttribute searchAttrs[] = {
     541                {kSecServiceItemAttr, 3, "SSH"},
     542                {kSecAccountItemAttr, filename_len, utf8_filename}
     543        };
     544        SecKeychainAttributeList searchAttrList =
     545            {sizeof(searchAttrs) / sizeof(searchAttrs[0]), searchAttrs};
     546        SecKeychainAttribute attrs[] = {
     547                {kSecLabelItemAttr, filename_len + 5, label},
     548                {kSecServiceItemAttr, 3, "SSH"},
     549                {kSecAccountItemAttr, filename_len, utf8_filename}
     550        };
     551        SecKeychainAttributeList attrList =
     552            {sizeof(attrs) / sizeof(attrs[0]), attrs};
     553        if (SecGenericPasswordCreate(&searchAttrList, &attrList, &passRef) !=
     554            noErr) {
     555                fprintf(stderr, "SecGenericPasswordCreate failed\n");
     556                goto err;
     557        }
     558        if (SecTrustedApplicationCreateFromPath("/usr/bin/ssh-agent", &apps[0])
     559            != noErr ||
     560            SecTrustedApplicationCreateFromPath("/usr/bin/ssh-add", &apps[1])
     561            != noErr ||
     562            SecTrustedApplicationCreateFromPath("/usr/bin/ssh", &apps[2])
     563            != noErr) {
     564                fprintf(stderr, "SecTrustedApplicationCreateFromPath failed\n");
     565                goto err;
     566        }
     567        if ((trustedlist = CFArrayCreate(NULL, (const void **)apps,
     568            sizeof(apps) / sizeof(apps[0]), &kCFTypeArrayCallBacks)) == NULL) {
     569                fprintf(stderr, "CFArrayCreate failed\n");
     570                goto err;
     571        }
     572        if (SecAccessCreate(cfstr_filename, trustedlist, &initialAccess)
     573            != noErr) {
     574                fprintf(stderr, "SecAccessCreate failed\n");
     575                goto err;
     576        }
     577        if (SecPasswordSetInitialAccess(passRef, initialAccess) != noErr) {
     578                fprintf(stderr, "SecPasswordSetInitialAccess failed\n");
     579                goto err;
     580        }
     581
     582        /* Request the passphrase from the user. */
     583        if ((path = CFURLCreateFromFileSystemRepresentation(NULL,
     584            (UInt8 *)filename, strlen(filename), false)) == NULL) {
     585                fprintf(stderr, "CFURLCreateFromFileSystemRepresentation failed\n");
     586                goto err;
     587        }
     588        if ((pathFinal = CFURLCopyLastPathComponent(path)) == NULL) {
     589                fprintf(stderr, "CFURLCopyLastPathComponent failed\n");
     590                goto err;
     591        }
     592        if (!((bundle_url = CFURLCreateWithFileSystemPath(NULL,
     593            CFSTR("/System/Library/CoreServices/"), kCFURLPOSIXPathStyle, true))
     594            != NULL && (bundle = CFBundleCreate(NULL, bundle_url)) != NULL &&
     595            (promptTemplate = CFCopyLocalizedStringFromTableInBundle(
     596            CFSTR("Enter your password for the SSH key \"%@\"."),
     597            CFSTR("OpenSSH"), bundle, "Text of the dialog asking the user for"
     598            "their passphrase.  The %@ will be replaced with the filename of a"
     599            "specific key.")) != NULL) &&
     600            (promptTemplate = CFStringCreateCopy(NULL,
     601            CFSTR("Enter your password for the SSH key \"%@\"."))) == NULL) {
     602                fprintf(stderr, "CFStringCreateCopy failed\n");
     603                goto err;
     604        }
     605        if ((prompt = CFStringCreateWithFormat(NULL, NULL, promptTemplate,
     606            pathFinal)) == NULL) {
     607                fprintf(stderr, "CFStringCreateWithFormat failed\n");
     608                goto err;
     609        }
     610        switch (SecPasswordAction(passRef, prompt,
     611            kSecPasswordGet|kSecPasswordFail, &length, &data)) {
     612        case noErr:
     613                result = xmalloc(length + 1);
     614                memcpy(result, data, length);
     615                result[length] = '\0';
     616
     617                /* Save password in keychain if requested. */
     618                if (noErr != SecPasswordAction(passRef, CFSTR(""), kSecPasswordSet, &length, &data))
     619                        fprintf(stderr, "Saving password to keychain failed\n");
     620
     621                /* Add password to agent. */
     622                char *comment = NULL;
     623                Key *private = key_load_private(filename, result, &comment);
     624                if (NULL == private)
     625                        break;
     626                if (ssh_add_identity_constrained(ac, private, comment, 0, 0))
     627                        fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
     628                else
     629                        fprintf(stderr, "Could not add identity: %s\n", filename);
     630                xfree(comment);
     631                key_free(private);
     632                break;
     633        case errAuthorizationCanceled:
     634                result = xmalloc(1);
     635                *result = '\0';
     636                break;
     637        default:
     638                goto err;
     639        }
     640
     641err:    /* Clean up. */
     642        if (cfstr_relative_filename)
     643                CFRelease(cfstr_relative_filename);
     644        if (cfurl_relative_filename)
     645                CFRelease(cfurl_relative_filename);
     646        if (cfurl_filename)
     647                CFRelease(cfurl_filename);
     648        if (cfstr_filename)
     649                CFRelease(cfstr_filename);
     650        if (cfdata_filename)
     651                CFRelease(cfdata_filename);
     652        if (label)
     653                xfree(label);
     654        if (passRef)
     655                CFRelease(passRef);
     656        if (apps[0])
     657                CFRelease(apps[0]);
     658        if (apps[1])
     659                CFRelease(apps[1]);
     660        if (apps[2])
     661                CFRelease(apps[2]);
     662        if (trustedlist)
     663                CFRelease(trustedlist);
     664        if (initialAccess)
     665                CFRelease(initialAccess);
     666        if (path)
     667                CFRelease(path);
     668        if (pathFinal)
     669                CFRelease(pathFinal);
     670        if (bundle_url)
     671                CFRelease(bundle_url);
     672        if (bundle)
     673                CFRelease(bundle);
     674        if (promptTemplate)
     675                CFRelease(promptTemplate);
     676        if (prompt)
     677                CFRelease(prompt);
     678        if (ac)
     679                ssh_close_authentication_connection(ac);
     680
     681        return result;
     682
     683#else
     684
     685        /*
     686         * keychain_read_passphrase
     687         * no implementation
     688         */
     689
     690        return NULL;
     691
     692#endif
     693
     694}
  • new file keychain.h

    diff --git a/keychain.h b/keychain.h
    new file mode 100644
    index 0000000..3ab1a6b
    - +  
     1/*
     2 * Copyright (c) 2007 Apple Inc. All rights reserved.
     3 *
     4 * @APPLE_BSD_LICENSE_HEADER_START@
     5 *
     6 * Redistribution and use in source and binary forms, with or without
     7 * modification, are permitted provided that the following conditions
     8 * are met:
     9 *
     10 * 1.  Redistributions of source code must retain the above copyright
     11 *     notice, this list of conditions and the following disclaimer.
     12 * 2.  Redistributions in binary form must reproduce the above copyright
     13 *     notice, this list of conditions and the following disclaimer in the
     14 *     documentation and/or other materials provided with the distribution.
     15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of its
     16 *     contributors may be used to endorse or promote products derived from
     17 *     this software without specific prior written permission.
     18 *
     19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 *
     30 * @APPLE_BSD_LICENSE_HEADER_END@
     31 */
     32
     33/*
     34 * KEYCHAIN indicates that keychain functionality is present.
     35 * KEYCHAIN_* indicates the implementation to use, and implies KEYCHAIN.
     36 */
     37#if defined(__APPLE_KEYCHAIN__)
     38#define KEYCHAIN
     39#endif
     40
     41void     store_in_keychain(const char *filename, const char *passphrase);
     42void     remove_from_keychain(const char *filename);
     43int      add_identities_using_keychain(
     44             int (*add_identity)(const char *, const char *));
     45char    *keychain_read_passphrase(const char *filename, int oAskPassGUI);
  • readconf.c

    diff --git a/readconf.c b/readconf.c
    index 60befde..0fe8fb1 100644
    a b typedef enum { 
    137137        oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
    138138        oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
    139139        oKexAlgorithms, oIPQoS, oRequestTTY,
     140#ifdef __APPLE_KEYCHAIN__
     141        oAskPassGUI,
     142#endif
    140143        oDeprecated, oUnsupported
    141144} OpCodes;
    142145
    static struct { 
    257260        { "kexalgorithms", oKexAlgorithms },
    258261        { "ipqos", oIPQoS },
    259262        { "requesttty", oRequestTTY },
    260 
     263#ifdef __APPLE_KEYCHAIN__
     264        { "askpassgui", oAskPassGUI },
     265#endif
    261266        { NULL, oBadOption }
    262267};
    263268
    parse_int: 
    10741079                        *intptr = value;
    10751080                break;
    10761081
     1082#ifdef __APPLE_KEYCHAIN__
     1083        case oAskPassGUI:
     1084                intptr = &options->ask_pass_gui;
     1085                goto parse_flag;
     1086#endif
     1087
    10771088        case oDeprecated:
    10781089                debug("%s line %d: Deprecated option \"%s\"",
    10791090                    filename, linenum, keyword);
    initialize_options(Options * options) 
    12381249        options->ip_qos_interactive = -1;
    12391250        options->ip_qos_bulk = -1;
    12401251        options->request_tty = -1;
     1252#ifdef __APPLE_KEYCHAIN__
     1253        options->ask_pass_gui = -1;
     1254#endif
    12411255}
    12421256
    12431257/*
    fill_default_options(Options * options) 
    14081422                options->ip_qos_bulk = IPTOS_THROUGHPUT;
    14091423        if (options->request_tty == -1)
    14101424                options->request_tty = REQUEST_TTY_AUTO;
     1425#ifdef __APPLE_KEYCHAIN__
     1426        if (options->ask_pass_gui == -1)
     1427                options->ask_pass_gui = 1;
     1428#endif
    14111429        /* options->local_command should not be set by default */
    14121430        /* options->proxy_command should not be set by default */
    14131431        /* options->user will be set in the main program if appropriate */
  • readconf.h

    diff --git a/readconf.h b/readconf.h
    index 617686f..150e95b 100644
    a b typedef struct { 
    139139        int     use_roaming;
    140140
    141141        int     request_tty;
     142
     143#ifdef __APPLE_KEYCHAIN__
     144        int ask_pass_gui;
     145#endif
    142146}       Options;
    143147
    144148#define SSHCTL_MASTER_NO        0
  • scp.1

    diff --git a/scp.1 b/scp.1
    index 577dd52..c93fb0e 100644
    a b  
    1919.Sh SYNOPSIS
    2020.Nm scp
    2121.Bk -words
    22 .Op Fl 12346BCpqrv
     22.Op Fl 12346BCEpqrv
    2323.Op Fl c Ar cipher
    2424.Op Fl F Ar ssh_config
    2525.Op Fl i Ar identity_file
    Passes the 
    9797flag to
    9898.Xr ssh 1
    9999to enable compression.
     100.It Fl E
     101Preserves extended attributes, resource forks, and ACLs.  Requires both ends to be running Mac OS X 10.4 or later.
    100102.It Fl c Ar cipher
    101103Selects the cipher to use for encrypting the data transfer.
    102104This option is directly passed to
  • scp.c

    diff --git a/scp.c b/scp.c
    index 18b2597..439530d 100644
    a b  
    7878#ifdef HAVE_SYS_STAT_H
    7979# include <sys/stat.h>
    8080#endif
     81#ifdef __APPLE_XSAN__
     82#include <sys/mount.h>
     83#endif
    8184#ifdef HAVE_POLL_H
    8285#include <poll.h>
    8386#else
     
    114117#include "misc.h"
    115118#include "progressmeter.h"
    116119
     120#ifdef HAVE_COPYFILE_H
     121#include <libgen.h>
     122#include <copyfile.h>
     123#endif
     124
    117125extern char *__progname;
    118126
    119127#define COPY_BUFLEN     16384
    char *ssh_program = _PATH_SSH_PROGRAM; 
    150158/* This is used to store the pid of ssh_program */
    151159pid_t do_cmd_pid = -1;
    152160
     161#ifdef HAVE_COPYFILE
     162int copy_xattr = 0;
     163int md_flag = 0;
     164#endif
     165
     166
    153167static void
    154168killchild(int signo)
    155169{
    main(int argc, char **argv) 
    395409        addargs(&args, "-oClearAllForwardings=yes");
    396410
    397411        fflag = tflag = 0;
     412#if HAVE_COPYFILE
     413        while ((ch = getopt(argc, argv, "dfl:prtvBCEc:i:P:q12346S:o:F:")) != -1)
     414#else
    398415        while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
     416#endif
    399417                switch (ch) {
    400418                /* User-visible flags. */
    401419                case '1':
    main(int argc, char **argv) 
    456474                        showprogress = 0;
    457475                        break;
    458476
     477#ifdef HAVE_COPYFILE
     478                case 'E':
     479                        copy_xattr = 1;
     480                        break;
     481#endif
    459482                /* Server options. */
    460483                case 'd':
    461484                        targetshouldbedirectory = 1;
    main(int argc, char **argv) 
    505528        remin = remout = -1;
    506529        do_cmd_pid = -1;
    507530        /* Command to be executed on remote system using "ssh". */
     531#if HAVE_COPYFILE
     532        (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s%s",
     533            copy_xattr ? " -E" : "",
     534#else
    508535        (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
     536#endif
    509537            verbose_mode ? " -v" : "",
    510538            iamrecursive ? " -r" : "", pflag ? " -p" : "",
    511539            targetshouldbedirectory ? " -d" : "");
    source(int argc, char **argv) 
    729757        int fd = -1, haderr, indx;
    730758        char *last, *name, buf[2048], encname[MAXPATHLEN];
    731759        int len;
     760#if HAVE_COPYFILE
     761        char md_name[MAXPATHLEN];
     762        char *md_tmp;
     763#endif
    732764
    733765        for (indx = 0; indx < argc; ++indx) {
    734766                name = argv[indx];
    source(int argc, char **argv) 
    736768                len = strlen(name);
    737769                while (len > 1 && name[len-1] == '/')
    738770                        name[--len] = '\0';
     771#if HAVE_COPYFILE
     772md_next:
     773                statbytes = 0;
     774                if (md_flag) {
     775                    fd = open(md_tmp, O_RDONLY, 0);
     776                    unlink(md_tmp);
     777                    free(md_tmp);
     778                    if (fd < 0)
     779                        goto syserr;
     780                } else {
     781#endif
    739782                if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0)
    740783                        goto syserr;
    741784                if (strchr(name, '\n') != NULL) {
    742785                        strnvis(encname, name, sizeof(encname), VIS_NL);
    743786                        name = encname;
    744787                }
     788#if HAVE_COPYFILE
     789                }
     790#endif
    745791                if (fstat(fd, &stb) < 0) {
    746792syserr:                 run_err("%s: %s", name, strerror(errno));
    747793                        goto next;
    next: if (fd != -1) { 
    838884                else
    839885                        run_err("%s: %s", name, strerror(haderr));
    840886                (void) response();
     887#ifdef HAVE_COPYFILE
     888                if (copy_xattr && md_flag == 0)
     889                {
     890                    if (!copyfile(name, NULL, 0,
     891                            COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_CHECK))
     892                        continue;
     893
     894                    /*
     895                     * this file will hold the actual metadata
     896                     * to be transferred
     897                     */
     898                    md_tmp = strdup("/tmp/scp.md.XXXXXX");
     899                    md_tmp = mktemp(md_tmp);
     900
     901                    if(copyfile(name, md_tmp, 0,
     902                                COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_PACK) == 0)
     903                    {
     904                        /*
     905                         * this is the fake name to display
     906                         */
     907                        snprintf(md_name, sizeof md_name, "%s/._%s", dirname(name), basename(name));
     908                        name = md_name;
     909                        md_flag = 1;
     910                        if (verbose_mode)
     911                            fprintf(stderr, "copyfile(%s, %s, PACK)\n", name, md_tmp);
     912                        goto md_next;
     913                    }
     914                } else
     915                    md_flag = 0;
     916#endif
    841917        }
    842918}
    843919
    sink(int argc, char **argv) 
    9321008        if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
    9331009                targisdir = 1;
    9341010        for (first = 1;; first = 0) {
     1011#if HAVE_COPYFILE
     1012                char md_src[MAXPATHLEN];
     1013                char md_dst[MAXPATHLEN];
     1014#endif
    9351015                cp = buf;
    9361016                if (atomicio(read, remin, cp, 1) != 1)
    9371017                        return;
    sink(int argc, char **argv) 
    10651145                }
    10661146                omode = mode;
    10671147                mode |= S_IWRITE;
     1148
     1149#if HAVE_COPYFILE
     1150                if (copy_xattr && !strncmp(basename(curfile), "._", 2))
     1151                {
     1152                        int mdfd;
     1153                        if (targisdir)
     1154                        {
     1155                            snprintf(md_src, sizeof md_src, "%s.XXXXXX", np);
     1156                            snprintf(md_dst, sizeof md_dst, "%s/%s",
     1157                                    dirname(np), basename(np) + 2);
     1158                            if((mdfd = mkstemp(md_src)) < 0)
     1159                                continue;
     1160                        }
     1161                        else
     1162                        {
     1163                            snprintf(md_src, sizeof md_src, "%s/._%s.XXXXXX",
     1164                                    dirname(np), basename(np));
     1165                            snprintf(md_dst, sizeof md_dst, "%s", np);
     1166                            if((mdfd = mkstemp(md_src)) < 0)
     1167                                continue;
     1168                        }
     1169                        if (mdfd >= 0)
     1170                                close(mdfd);
     1171                        np = md_src;
     1172                }
     1173#endif
    10681174                if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
    10691175bad:                    run_err("%s: %s", np, strerror(errno));
    10701176                        continue;
    10711177                }
     1178#ifdef __APPLE_XSAN__
     1179                {
     1180                        /*
     1181                         * Pre-allocate blocks for the destination file.
     1182                         */
     1183                        fstore_t fst;
     1184
     1185                        fst.fst_flags = 0;
     1186                        fst.fst_posmode = F_PEOFPOSMODE;
     1187                        fst.fst_offset = 0;
     1188                        fst.fst_length = size;
     1189                               
     1190                        (void) fcntl(ofd, F_PREALLOCATE, &fst);
     1191                }
     1192#endif /* __APPLE_XSAN__ */             
    10721193                (void) atomicio(vwrite, remout, "", 1);
    10731194                if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
    10741195                        (void) close(ofd);
    bad: run_err("%s: %s", np, strerror(errno)); 
    11531274                        wrerrno = errno;
    11541275                }
    11551276                (void) response();
     1277#ifdef HAVE_COPYFILE
     1278                if (copy_xattr && strncmp(basename(np), "._", 2) == 0)
     1279                {
     1280                        if (verbose_mode)
     1281                            fprintf(stderr, "copyfile(%s, %s, UNPACK)\n", md_src, md_dst);
     1282                        if(!copyfile(md_src, md_dst, 0,
     1283                            COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_UNPACK) < 0)
     1284                        {
     1285                            snprintf(md_dst, sizeof md_dst, "%s/._%s",
     1286                                    dirname(md_dst), basename(md_dst));
     1287                            rename(md_src, md_dst);
     1288                        } else
     1289                            unlink(md_src);
     1290                        if (setimes && wrerr == NO) {
     1291                                setimes = 0;
     1292                                if (utimes(md_dst, tv) < 0) {
     1293                                        run_err("%s: set times: %s",
     1294                                        np, strerror(errno));
     1295                                        wrerr = DISPLAYED;
     1296                                }
     1297                        }
     1298                } else
     1299#endif
    11561300                if (setimes && wrerr == NO) {
    11571301                        setimes = 0;
    11581302                        if (utimes(np, tv) < 0) {
    void 
    12141358usage(void)
    12151359{
    12161360        (void) fprintf(stderr,
     1361#if HAVE_COPYFILE
     1362            "usage: scp [-12346BCEpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
     1363#else
    12171364            "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
     1365#endif
    12181366            "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
    12191367            "           [[user@]host1:]file1 ... [[user@]host2:]file2\n");
    12201368        exit(1);
  • servconf.c

    diff --git a/servconf.c b/servconf.c
    index 756a3a2..0e2678e 100644
    a b fill_default_server_options(ServerOptions *options) 
    148148{
    149149        /* Portable-specific options */
    150150        if (options->use_pam == -1)
    151                 options->use_pam = 0;
     151                options->use_pam = 1;
    152152
    153153        /* Standard Options */
    154154        if (options->protocol == SSH_PROTO_UNKNOWN)
    fill_default_server_options(ServerOptions *options) 
    237237        if (options->gss_store_rekey == -1)
    238238                options->gss_store_rekey = 0;
    239239        if (options->password_authentication == -1)
    240                 options->password_authentication = 1;
     240                options->password_authentication = 0;
    241241        if (options->kbd_interactive_authentication == -1)
    242242                options->kbd_interactive_authentication = 0;
    243243        if (options->challenge_response_authentication == -1)
    match_cfg_line_group(const char *grps, int line, const char *user) 
    602602        if ((pw = getpwnam(user)) == NULL) {
    603603                debug("Can't match group at line %d because user %.100s does "
    604604                    "not exist", line, user);
    605         } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
     605        } else if (ga_init(pw) == 0) {
    606606                debug("Can't Match group because user %.100s not in any group "
    607607                    "at line %d", user, line);
    608608        } else if (ga_match_pattern_list(grps) != 1) {
  • session.c

    diff --git a/session.c b/session.c
    index 6a70400..42e6fac 100644
    a b session_pty_req(Session *s) 
    20632063                n_bytes = packet_remaining();
    20642064        tty_parse_modes(s->ttyfd, &n_bytes);
    20652065
     2066#ifndef __APPLE_PRIVPTY__
    20662067        if (!use_privsep)
    20672068                pty_setowner(s->pw, s->tty);
     2069#endif
    20682070
    20692071        /* Set window size from the packet. */
    20702072        pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
    session_pty_cleanup2(Session *s) 
    23042306        if (s->pid != 0)
    23052307                record_logout(s->pid, s->tty, s->pw->pw_name);
    23062308
     2309#ifndef __APPLE_PRIVPTY__
    23072310        /* Release the pseudo-tty. */
    23082311        if (getuid() == 0)
    23092312                pty_release(s->tty);
     2313#endif
    23102314
    23112315        /*
    23122316         * Close the server side of the socket pairs.  We must do this after
  • ssh-add.0

    diff --git a/ssh-add.0 b/ssh-add.0
    index e1e2a64..74ee18a 100644
    a b  
    11SSH-ADD(1)                 OpenBSD Reference Manual                 SSH-ADD(1)
    22
    33NAME
    4      ssh-add - adds private key identities to the authentication agent
     4     ssh-add -- adds private key identities to the authentication agent
    55
    66SYNOPSIS
    7      ssh-add [-cDdLlXx] [-t life] [file ...]
     7     ssh-add [-cDdLlXxKk] [-t life] [file ...]
    88     ssh-add -s pkcs11
    99     ssh-add -e pkcs11
    1010
    DESCRIPTION 
    6363
    6464     -x      Lock the agent with a password.
    6565
     66     -K      When adding identities, each passphrase will also be stored in
     67             your keychain.  When removing identities with -d, each passphrase
     68             will be removed from your keychain.
     69
     70     -k      Add identities to the agent using any passphrases stored in your
     71             keychain.
     72
    6673ENVIRONMENT
    6774     DISPLAY and SSH_ASKPASS
    6875             If ssh-add needs a passphrase, it will read the passphrase from
  • ssh-add.1

    diff --git a/ssh-add.1 b/ssh-add.1
    index fd48ff9..0bd1114 100644
    a b  
    4343.Nd adds private key identities to the authentication agent
    4444.Sh SYNOPSIS
    4545.Nm ssh-add
    46 .Op Fl cDdLlXx
     46.Op Fl cDdLlXxKk
    4747.Op Fl t Ar life
    4848.Op Ar
    4949.Nm ssh-add
    specified in 
    127127Unlock the agent.
    128128.It Fl x
    129129Lock the agent with a password.
     130.It Fl K
     131When adding identities, each passphrase will also be stored in your
     132keychain.  When removing identities with -d, each passphrase will be
     133removed from your keychain.
     134.It Fl k
     135Add identities to the agent using any passphrases stored in your keychain.
    130136.El
    131137.Sh ENVIRONMENT
    132138.Bl -tag -width Ds
  • ssh-add.c

    diff --git a/ssh-add.c b/ssh-add.c
    index 6d5e2a9..9621451 100644
    a b  
    6262#include "authfile.h"
    6363#include "pathnames.h"
    6464#include "misc.h"
     65#include "keychain.h"
    6566
    6667/* argv0 */
    6768extern char *__progname;
    clear_pass(void) 
    9697}
    9798
    9899static int
    99 delete_file(AuthenticationConnection *ac, const char *filename)
     100add_from_keychain(AuthenticationConnection *ac)
     101{
     102        if (ssh_add_from_keychain(ac) == 0)
     103                return -1;
     104
     105        fprintf(stderr, "Added keychain identities.\n");
     106        return 0;
     107}
     108
     109static int
     110delete_file(AuthenticationConnection *ac, int keychain, const char *filename)
    100111{
    101112        Key *public;
    102113        char *comment = NULL;
    103114        int ret = -1;
    104115
     116        if (keychain)
     117                remove_from_keychain(filename);
    105118        public = key_load_public(filename, &comment);
    106119        if (public == NULL) {
    107120                printf("Bad key file %s\n", filename);
    delete_all(AuthenticationConnection *ac) 
    139152}
    140153
    141154static int
    142 add_file(AuthenticationConnection *ac, const char *filename)
     155add_file(AuthenticationConnection *ac, int keychain, const char *filename)
    143156{
    144157        Key *private, *cert;
    145158        char *comment = NULL;
    add_file(AuthenticationConnection *ac, const char *filename) 
    176189
    177190        /* At first, try empty passphrase */
    178191        private = key_parse_private(&keyblob, filename, "", &comment);
     192        if (keychain && private != NULL)
     193                store_in_keychain(filename, "");
    179194        if (comment == NULL)
    180195                comment = xstrdup(filename);
    181196        /* try last */
    182         if (private == NULL && pass != NULL)
     197        if (private == NULL && pass != NULL) {
    183198                private = key_parse_private(&keyblob, filename, pass, NULL);
     199                if (keychain && private != NULL)
     200                        store_in_keychain(filename, pass);
     201        }
    184202        if (private == NULL) {
    185203                /* clear passphrase since it did not work */
    186204                clear_pass();
    add_file(AuthenticationConnection *ac, const char *filename) 
    196214                        }
    197215                        private = key_parse_private(&keyblob, filename, pass,
    198216                            &comment);
    199                         if (private != NULL)
     217                        if (private != NULL) {
     218                                if (keychain)
     219                                        store_in_keychain(filename, pass);
    200220                                break;
     221                        }
    201222                        clear_pass();
    202223                        snprintf(msg, sizeof msg,
    203224                            "Bad passphrase, try again for %.200s: ", comment);
    lock_agent(AuthenticationConnection *ac, int lock) 
    347368}
    348369
    349370static int
    350 do_file(AuthenticationConnection *ac, int deleting, char *file)
     371do_file(AuthenticationConnection *ac, int deleting, int keychain, char *file)
    351372{
    352373        if (deleting) {
    353                 if (delete_file(ac, file) == -1)
     374                if (delete_file(ac, keychain, file) == -1)
    354375                        return -1;
    355376        } else {
    356                 if (add_file(ac, file) == -1)
     377                if (add_file(ac, keychain, file) == -1)
    357378                        return -1;
    358379        }
    359380        return 0;
    usage(void) 
    374395        fprintf(stderr, "  -c          Require confirmation to sign using identities\n");
    375396        fprintf(stderr, "  -s pkcs11   Add keys from PKCS#11 provider.\n");
    376397        fprintf(stderr, "  -e pkcs11   Remove keys provided by PKCS#11 provider.\n");
     398#ifdef KEYCHAIN
     399        fprintf(stderr, "  -k          Add all identities stored in your keychain.\n");
     400        fprintf(stderr, "  -K          Store passphrases in your keychain.\n");
     401        fprintf(stderr, "              With -d, remove passphrases from your keychain.\n");
     402#endif
    377403}
    378404
    379405int
    main(int argc, char **argv) 
    384410        AuthenticationConnection *ac = NULL;
    385411        char *pkcs11provider = NULL;
    386412        int i, ch, deleting = 0, ret = 0;
     413        int keychain = 0;
    387414
    388415        /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
    389416        sanitise_stdfd();
    main(int argc, char **argv) 
    400427                    "Could not open a connection to your authentication agent.\n");
    401428                exit(2);
    402429        }
    403         while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) {
     430        while ((ch = getopt(argc, argv, "lLcdDxXe:s:kKt:")) != -1) {
    404431                switch (ch) {
    405432                case 'l':
    406433                case 'L':
    main(int argc, char **argv) 
    422449                        if (delete_all(ac) == -1)
    423450                                ret = 1;
    424451                        goto done;
     452                case 'k':
     453                        if (add_from_keychain(ac) == -1)
     454                                ret = 1;
     455                        goto done;
     456                case 'K':
     457                        keychain = 1;
     458                        break;
    425459                case 's':
    426460                        pkcs11provider = optarg;
    427461                        break;
    main(int argc, char **argv) 
    452486        if (argc == 0) {
    453487                char buf[MAXPATHLEN];
    454488                struct passwd *pw;
     489                char *pw_dir;
    455490                struct stat st;
    456491                int count = 0;
    457492
    main(int argc, char **argv) 
    462497                        goto done;
    463498                }
    464499
     500                pw_dir = xstrdup(pw->pw_dir);
     501
    465502                for (i = 0; default_files[i]; i++) {
    466                         snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
     503                        snprintf(buf, sizeof(buf), "%s/%s", pw_dir,
    467504                            default_files[i]);
    468505                        if (stat(buf, &st) < 0)
    469506                                continue;
    470                         if (do_file(ac, deleting, buf) == -1)
     507                        if (do_file(ac, deleting, keychain, buf) == -1)
    471508                                ret = 1;
    472509                        else
    473510                                count++;
    474511                }
    475512                if (count == 0)
    476513                        ret = 1;
     514
     515                xfree(pw_dir);
    477516        } else {
    478517                for (i = 0; i < argc; i++) {
    479                         if (do_file(ac, deleting, argv[i]) == -1)
     518                        if (do_file(ac, deleting, keychain, argv[i]) == -1)
    480519                                ret = 1;
    481520                }
    482521        }
  • ssh-agent.c

    diff --git a/ssh-agent.c b/ssh-agent.c
    index b9498e6..a154096 100644
    a b  
    6565#include <time.h>
    6666#include <string.h>
    6767#include <unistd.h>
     68#ifdef __APPLE_LAUNCHD__
     69#include <launch.h>
     70#endif
    6871
    6972#include "xmalloc.h"
    7073#include "ssh.h"
     
    7275#include "buffer.h"
    7376#include "key.h"
    7477#include "authfd.h"
     78#include "authfile.h"
    7579#include "compat.h"
    7680#include "log.h"
    7781#include "misc.h"
     82#include "keychain.h"
    7883
    7984#ifdef ENABLE_PKCS11
    8085#include "ssh-pkcs11.h"
    process_remove_smartcard_key(SocketEntry *e) 
    793798}
    794799#endif /* ENABLE_PKCS11 */
    795800
     801static int
     802add_identity_callback(const char *filename, const char *passphrase)
     803{
     804        Key *k;
     805        int version;
     806        Idtab *tab;
     807
     808        if ((k = key_load_private(filename, passphrase, NULL)) == NULL)
     809                return 1;
     810        switch (k->type) {
     811        case KEY_RSA:
     812        case KEY_RSA1:
     813                if (RSA_blinding_on(k->rsa, NULL) != 1) {
     814                        key_free(k);
     815                        return 1;
     816                }
     817                break;
     818        }
     819        version = k->type == KEY_RSA1 ? 1 : 2;
     820        tab = idtab_lookup(version);
     821        if (lookup_identity(k, version) == NULL) {
     822                Identity *id = xmalloc(sizeof(Identity));
     823                id->key = k;
     824                id->comment = xstrdup(filename);
     825                if (id->comment == NULL) {
     826                        key_free(k);
     827                        return 1;
     828                }
     829                id->death = 0;
     830                id->confirm = 0;
     831                TAILQ_INSERT_TAIL(&tab->idlist, id, next);
     832                tab->nentries++;
     833        } else {
     834                key_free(k);
     835                return 1;
     836        }
     837
     838        return 0;
     839}
     840
     841static void
     842process_add_from_keychain(SocketEntry *e)
     843{
     844        int result;
     845
     846        result = add_identities_using_keychain(&add_identity_callback);
     847
     848        /* e will be NULL when ssh-agent adds keys on its own at startup */
     849        if (e) {
     850                buffer_put_int(&e->output, 1);
     851                buffer_put_char(&e->output,
     852                    result ? SSH_AGENT_FAILURE : SSH_AGENT_SUCCESS);
     853        }
     854}
     855
    796856/* dispatch incoming messages */
    797857
    798858static void
    process_message(SocketEntry *e) 
    885945                process_remove_smartcard_key(e);
    886946                break;
    887947#endif /* ENABLE_PKCS11 */
     948        case SSH_AGENTC_ADD_FROM_KEYCHAIN:
     949                process_add_from_keychain(e);
     950                break;
    888951        default:
    889952                /* Unknown message.  Respond with failure. */
    890953                error("Unknown message %d", type);
    usage(void) 
    11261189int
    11271190main(int ac, char **av)
    11281191{
     1192#ifdef __APPLE_LAUNCHD__
     1193        int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, l_flag = 0;
     1194#else
    11291195        int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0;
     1196#endif
    11301197        int sock, fd, ch, result, saved_errno;
    11311198        u_int nalloc;
    11321199        char *shell, *format, *pidstr, *agentsocket = NULL;
    main(int ac, char **av) 
    11601227        __progname = ssh_get_progname(av[0]);
    11611228        seed_rng();
    11621229
     1230#ifdef __APPLE_LAUNCHD__
     1231        while ((ch = getopt(ac, av, "cdklsa:t:")) != -1) {
     1232#else
    11631233        while ((ch = getopt(ac, av, "cdksa:t:")) != -1) {
     1234#endif
    11641235                switch (ch) {
    11651236                case 'c':
    11661237                        if (s_flag)
    main(int ac, char **av) 
    11701241                case 'k':
    11711242                        k_flag++;
    11721243                        break;
     1244#ifdef __APPLE_LAUNCHD__
     1245                case 'l':
     1246                        l_flag++;
     1247                        break;
     1248#endif
    11731249                case 's':
    11741250                        if (c_flag)
    11751251                                usage();
    main(int ac, char **av) 
    11961272        ac -= optind;
    11971273        av += optind;
    11981274
     1275#ifdef __APPPLE_LAUNCHD__
     1276        if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || l_flag))
     1277#else
    11991278        if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
     1279#endif
    12001280                usage();
    12011281
    12021282        if (ac == 0 && !c_flag && !s_flag) {
    main(int ac, char **av) 
    12521332         * Create socket early so it will exist before command gets run from
    12531333         * the parent.
    12541334         */
     1335#ifdef __APPLE_LAUNCHD__
     1336        if (l_flag) {
     1337                launch_data_t resp, msg, tmp;
     1338                size_t listeners_i;
     1339
     1340                msg = launch_data_new_string(LAUNCH_KEY_CHECKIN);
     1341
     1342                resp = launch_msg(msg);
     1343
     1344                if (NULL == resp) {
     1345                        perror("launch_msg");
     1346                        exit(1);
     1347                }
     1348                launch_data_free(msg);
     1349                switch (launch_data_get_type(resp)) {
     1350                case LAUNCH_DATA_ERRNO:
     1351                        errno = launch_data_get_errno(resp);
     1352                        perror("launch_msg response");
     1353                        exit(1);
     1354                case LAUNCH_DATA_DICTIONARY:
     1355                        break;
     1356                default:
     1357                        fprintf(stderr, "launch_msg unknown response");
     1358                        exit(1);
     1359                }
     1360                tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS);
     1361
     1362                if (NULL == tmp) {
     1363                        fprintf(stderr, "no sockets\n");
     1364                        exit(1);
     1365                }
     1366
     1367                tmp = launch_data_dict_lookup(tmp, "Listeners");
     1368
     1369                if (NULL == tmp) {
     1370                        fprintf(stderr, "no known listeners\n");
     1371                        exit(1);
     1372                }
     1373
     1374                for (listeners_i = 0; listeners_i < launch_data_array_get_count(tmp); listeners_i++) {
     1375                        launch_data_t obj_at_ind = launch_data_array_get_index(tmp, listeners_i);
     1376                        new_socket(AUTH_SOCKET, launch_data_get_fd(obj_at_ind));
     1377                }
     1378
     1379                launch_data_free(resp);
     1380        } else {
     1381#endif
    12551382        sock = socket(AF_UNIX, SOCK_STREAM, 0);
    12561383        if (sock < 0) {
    12571384                perror("socket");
    main(int ac, char **av) 
    12731400                perror("listen");
    12741401                cleanup_exit(1);
    12751402        }
     1403#ifdef __APPLE_LAUNCHD__
     1404        }
     1405#endif
     1406
     1407#ifdef __APPLE_LAUNCHD__
     1408        if (l_flag)
     1409                goto skip2;
     1410#endif
    12761411
    12771412        /*
    12781413         * Fork, and have the parent execute the command, if any, or present
    skip: 
    13451480        pkcs11_init(0);
    13461481#endif
    13471482        new_socket(AUTH_SOCKET, sock);
     1483skip2:
    13481484        if (ac > 0)
    13491485                parent_alive_interval = 10;
    13501486        idtab_init();
    skip: 
    13551491        signal(SIGTERM, cleanup_handler);
    13561492        nalloc = 0;
    13571493
     1494#ifdef KEYCHAIN
     1495        process_add_from_keychain(NULL);
     1496#endif
     1497
    13581498        while (1) {
    13591499                prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
    13601500                result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
  • ssh-keysign.8

    diff --git a/ssh-keysign.8 b/ssh-keysign.8
    index 5e09e02..612c8f8 100644
    a b accessible to others. 
    7171Since they are readable only by root,
    7272.Nm
    7373must be set-uid root if host-based authentication is used.
     74Note that
     75.Nm
     76is not set-uid by default on Mac OS X.
    7477.Pp
    7578.It Pa /etc/ssh/ssh_host_dsa_key-cert.pub
    7679.It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub
  • sshconnect1.c

    diff --git a/sshconnect1.c b/sshconnect1.c
    index fd07bbf..f9eaeba 100644
    a b  
    4747#include "canohost.h"
    4848#include "hostfile.h"
    4949#include "auth.h"
     50#include "keychain.h"
    5051
    5152/* Session id for the current session. */
    5253u_char session_id[16];
    try_rsa_authentication(int idx) 
    260261                snprintf(buf, sizeof(buf),
    261262                    "Enter passphrase for RSA key '%.100s': ", comment);
    262263                for (i = 0; i < options.number_of_password_prompts; i++) {
     264#ifdef __APPLE_KEYCHAIN__
     265                        passphrase = keychain_read_passphrase(comment, options.ask_pass_gui);
     266                        if (passphrase == NULL)
     267#endif
    263268                        passphrase = read_passphrase(buf, 0);
    264269                        if (strcmp(passphrase, "") != 0) {
    265270                                private = key_load_private_type(KEY_RSA1,
  • sshconnect2.c

    diff --git a/sshconnect2.c b/sshconnect2.c
    index 3ddef32..a8ed741 100644
    a b  
    7272#include "hostfile.h"
    7373#include "schnorr.h"
    7474#include "jpake.h"
     75#include "keychain.h"
    7576
    7677#ifdef GSSAPI
    7778#include "ssh-gss.h"
    load_identity_file(char *filename) 
    14471448                snprintf(prompt, sizeof prompt,
    14481449                    "Enter passphrase for key '%.100s': ", filename);
    14491450                for (i = 0; i < options.number_of_password_prompts; i++) {
     1451#ifdef __APPLE_KEYCHAIN__
     1452                        passphrase = keychain_read_passphrase(filename, options.ask_pass_gui);
     1453                        if (passphrase == NULL)
     1454#endif
    14501455                        passphrase = read_passphrase(prompt, 0);
    14511456                        if (strcmp(passphrase, "") != 0) {
    14521457                                private = key_load_private_type(KEY_UNSPEC,
  • sshd.0

    diff --git a/sshd.0 b/sshd.0
    index e8b4983..471841c 100644
    a b FILES 
    617617
    618618SEE ALSO
    619619     scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1),
    620      ssh-keyscan(1), chroot(2), hosts_access(5), login.conf(5), moduli(5),
    621      sshd_config(5), inetd(8), sftp-server(8)
     620     ssh-keyscan(1), chroot(2), hosts_access(5), sshd_config(5)
     621     sftp-server(8)
    622622
    623623AUTHORS
    624624     OpenSSH is a derivative of the original and free ssh 1.2.12 release by
  • sshd.8

    diff --git a/sshd.8 b/sshd.8
    index a91be0f..18941a6 100644
    a b The content of this file is not sensitive; it can be world-readable. 
    950950.Xr ssh-keyscan 1 ,
    951951.Xr chroot 2 ,
    952952.Xr hosts_access 5 ,
    953 .Xr login.conf 5 ,
    954 .Xr moduli 5 ,
    955953.Xr sshd_config 5 ,
    956 .Xr inetd 8 ,
    957954.Xr sftp-server 8
    958955.Sh AUTHORS
    959956OpenSSH is a derivative of the original and free
  • sshd.c

    diff --git a/sshd.c b/sshd.c
    index 112a5f9..4773543 100644
    a b main(int ac, char **av) 
    20762076        audit_event(SSH_AUTH_SUCCESS);
    20772077#endif
    20782078
     2079#ifdef USE_PAM
     2080        if (options.use_pam) {
     2081                do_pam_setcred(1);
     2082                do_pam_session();
     2083        }
     2084#endif
    20792085#ifdef GSSAPI
    20802086        if (options.gss_authentication) {
    20812087                temporarily_use_uid(authctxt->pw);
    main(int ac, char **av) 
    20832089                restore_uid();
    20842090        }
    20852091#endif
    2086 #ifdef USE_PAM
    2087         if (options.use_pam) {
    2088                 do_pam_setcred(1);
    2089                 do_pam_session();
    2090         }
    2091 #endif
    20922092
    20932093        /*
    20942094         * In privilege separation, we fork another child and prepare
  • sshd_config

    diff --git a/sshd_config b/sshd_config
    index d02d7a7..53966ab 100644
    a b  
    3131
    3232# Logging
    3333# obsoletes QuietMode and FascistLogging
    34 #SyslogFacility AUTH
     34SyslogFacility AUTHPRIV
    3535#LogLevel INFO
    3636
    3737# Authentication:
    AuthorizedKeysFile .ssh/authorized_keys 
    5959# Don't read the user's ~/.rhosts and ~/.shosts files
    6060#IgnoreRhosts yes
    6161
    62 # To disable tunneled clear text passwords, change to no here!
    63 #PasswordAuthentication yes
     62# To disable tunneled clear text passwords, change to no here! Also,
     63# remember to set the UsePAM setting to 'no'.
     64#PasswordAuthentication no
    6465#PermitEmptyPasswords no
    6566
    6667# Change to no to disable s/key passwords
    AuthorizedKeysFile .ssh/authorized_keys 
    8788# If you just want the PAM account and session checks to run without
    8889# PAM authentication, then enable this but set PasswordAuthentication
    8990# and ChallengeResponseAuthentication to 'no'.
    90 #UsePAM no
     91# Also, PAM will deny null passwords by default.  If you need to allow
     92# null passwords, add the "     nullok" option to the end of the
     93# securityserver.so line in /etc/pam.d/sshd.
     94#UsePAM yes
    9195
    9296#AllowAgentForwarding yes
    9397#AllowTcpForwarding yes
  • sshd_config.0

    diff --git a/sshd_config.0 b/sshd_config.0
    index e19ca87..5bee36a 100644
    a b DESCRIPTION 
    436436
    437437     PasswordAuthentication
    438438             Specifies whether password authentication is allowed.  The
    439              default is ``yes''.
     439             default is ``no''.
    440440
    441441     PermitEmptyPasswords
    442442             When password authentication is allowed, it specifies whether the
    DESCRIPTION 
    619619             either PasswordAuthentication or ChallengeResponseAuthentication.
    620620
    621621             If UsePAM is enabled, you will not be able to run sshd(8) as a
    622              non-root user.  The default is ``no''.
     622             non-root user.  The default is ``yes''.
    623623
    624624     UsePrivilegeSeparation
    625625             Specifies whether sshd(8) separates privileges by creating an
  • sshd_config.5

    diff --git a/sshd_config.5 b/sshd_config.5
    index 76c95aa..adebac6 100644
    a b are refused if the number of unauthenticated connections reaches 
    794794.It Cm PasswordAuthentication
    795795Specifies whether password authentication is allowed.
    796796The default is
    797 .Dq yes .
     797.Dq no .
    798798.It Cm PermitEmptyPasswords
    799799When password authentication is allowed, it specifies whether the
    800800server allows login to accounts with empty password strings.
    is enabled, you will not be able to run 
    10891089.Xr sshd 8
    10901090as a non-root user.
    10911091The default is
    1092 .Dq no .
     1092.Dq yes .
    10931093.It Cm UsePrivilegeSeparation
    10941094Specifies whether
    10951095.Xr sshd 8