1 | --- a/Makefile.in 2008-11-05 06:20:46.000000000 +0100 |
---|
2 | +++ b/Makefile.in 2009-02-26 01:14:06.000000000 +0100 |
---|
3 | @@ -56,6 +56,7 @@ |
---|
4 | ENT=@ENT@ |
---|
5 | XAUTH_PATH=@XAUTH_PATH@ |
---|
6 | LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ |
---|
7 | +KEYCHAIN_LDFLAGS=@KEYCHAIN_LDFLAGS@ |
---|
8 | EXEEXT=@EXEEXT@ |
---|
9 | MANFMT=@MANFMT@ |
---|
10 | |
---|
11 | @@ -93,6 +94,8 @@ |
---|
12 | roaming_common.o roaming_serv.o \ |
---|
13 | sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o |
---|
14 | |
---|
15 | +KEYCHAINOBJS=keychain.o |
---|
16 | + |
---|
17 | MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out |
---|
18 | MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 |
---|
19 | MANTYPE = @MANTYPE@ |
---|
20 | @@ -125,6 +128,7 @@ |
---|
21 | $(LIBSSH_OBJS): Makefile.in config.h |
---|
22 | $(SSHOBJS): Makefile.in config.h |
---|
23 | $(SSHDOBJS): Makefile.in config.h |
---|
24 | +$(KEYCHAINOBJS): Makefile.in config.h |
---|
25 | |
---|
26 | .c.o: |
---|
27 | $(CC) $(CFLAGS) $(CPPFLAGS) -c $< |
---|
28 | @@ -138,8 +142,8 @@ |
---|
29 | $(AR) rv $@ $(LIBSSH_OBJS) |
---|
30 | $(RANLIB) $@ |
---|
31 | |
---|
32 | -ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) |
---|
33 | - $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) |
---|
34 | +ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) $(KEYCHAINOBJS) |
---|
35 | + $(LD) -o $@ $(SSHOBJS) $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) |
---|
36 | |
---|
37 | sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) |
---|
38 | $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) |
---|
39 | @@ -147,11 +151,11 @@ |
---|
40 | scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o |
---|
41 | $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
---|
42 | |
---|
43 | -ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o |
---|
44 | - $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
---|
45 | +ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o $(KEYCHAINOBJS) |
---|
46 | + $(LD) -o $@ ssh-add.o $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
---|
47 | |
---|
48 | -ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o |
---|
49 | - $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
---|
50 | +ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o $(KEYCHAINOBJS) |
---|
51 | + $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(KEYCHAINOBJS) $(LDFLAGS) $(KEYCHAIN_LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
---|
52 | |
---|
53 | ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o |
---|
54 | $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
---|
55 | @@ -255,7 +259,7 @@ |
---|
56 | $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) |
---|
57 | $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) |
---|
58 | $(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT) |
---|
59 | - $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) |
---|
60 | + $(INSTALL) -m 0711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) |
---|
61 | $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) |
---|
62 | $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) |
---|
63 | $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) |
---|
64 | --- a/audit-bsm.c 2008-02-25 11:05:04.000000000 +0100 |
---|
65 | +++ b/audit-bsm.c 2008-10-09 01:55:13.000000000 +0200 |
---|
66 | @@ -194,7 +194,12 @@ |
---|
67 | pid_t pid = getpid(); |
---|
68 | AuditInfoTermID tid = ssh_bsm_tid; |
---|
69 | |
---|
70 | - if (the_authctxt != NULL && the_authctxt->valid) { |
---|
71 | + if (the_authctxt == NULL) { |
---|
72 | + error("BSM audit: audit record internal error (NULL ctxt)"); |
---|
73 | + abort(); |
---|
74 | + } |
---|
75 | + |
---|
76 | + if (the_authctxt->valid) { |
---|
77 | uid = the_authctxt->pw->pw_uid; |
---|
78 | gid = the_authctxt->pw->pw_gid; |
---|
79 | } |
---|
80 | --- a/auth-pam.c 2008-03-11 12:58:25.000000000 +0100 |
---|
81 | +++ b/auth-pam.c 2008-09-26 18:10:49.000000000 +0200 |
---|
82 | @@ -793,10 +793,11 @@ |
---|
83 | xfree(msg); |
---|
84 | return (0); |
---|
85 | } |
---|
86 | - error("PAM: %s for %s%.100s from %.100s", msg, |
---|
87 | + error("PAM: %s for %s%.100s from %.100s via %s", msg, |
---|
88 | sshpam_authctxt->valid ? "" : "illegal user ", |
---|
89 | sshpam_authctxt->user, |
---|
90 | - get_remote_name_or_ip(utmp_len, options.use_dns)); |
---|
91 | + get_remote_name_or_ip(utmp_len, options.use_dns), |
---|
92 | + get_local_ipaddr(packet_get_connection_in())); |
---|
93 | /* FALLTHROUGH */ |
---|
94 | default: |
---|
95 | *num = 0; |
---|
96 | --- a/authfd.c 2006-09-01 07:38:36.000000000 +0200 |
---|
97 | +++ b/authfd.c 2008-04-18 00:15:22.000000000 +0200 |
---|
98 | @@ -689,6 +689,29 @@ |
---|
99 | return decode_reply(type); |
---|
100 | } |
---|
101 | |
---|
102 | +/* |
---|
103 | + * Adds identities using passphrases stored in the keychain. This call is not |
---|
104 | + * meant to be used by normal applications. |
---|
105 | + */ |
---|
106 | + |
---|
107 | +int |
---|
108 | +ssh_add_from_keychain(AuthenticationConnection *auth) |
---|
109 | +{ |
---|
110 | + Buffer msg; |
---|
111 | + int type; |
---|
112 | + |
---|
113 | + buffer_init(&msg); |
---|
114 | + buffer_put_char(&msg, SSH_AGENTC_ADD_FROM_KEYCHAIN); |
---|
115 | + |
---|
116 | + if (ssh_request_reply(auth, &msg, &msg) == 0) { |
---|
117 | + buffer_free(&msg); |
---|
118 | + return 0; |
---|
119 | + } |
---|
120 | + type = buffer_get_char(&msg); |
---|
121 | + buffer_free(&msg); |
---|
122 | + return decode_reply(type); |
---|
123 | +} |
---|
124 | + |
---|
125 | int |
---|
126 | decode_reply(int type) |
---|
127 | { |
---|
128 | --- a/authfd.h 2006-08-05 04:39:39.000000000 +0200 |
---|
129 | +++ b/authfd.h 2008-04-18 00:15:22.000000000 +0200 |
---|
130 | @@ -49,6 +49,9 @@ |
---|
131 | #define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 |
---|
132 | #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 |
---|
133 | |
---|
134 | +/* keychain */ |
---|
135 | +#define SSH_AGENTC_ADD_FROM_KEYCHAIN 27 |
---|
136 | + |
---|
137 | #define SSH_AGENT_CONSTRAIN_LIFETIME 1 |
---|
138 | #define SSH_AGENT_CONSTRAIN_CONFIRM 2 |
---|
139 | |
---|
140 | --- a/auth.c 2011-05-29 13:40:42.000000000 +0200 |
---|
141 | +++ b/auth.c 2011-09-20 20:54:26.000000000 +0200 |
---|
142 | @@ -209,7 +209,7 @@ |
---|
143 | } |
---|
144 | if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { |
---|
145 | /* Get the user's group access list (primary and supplementary) */ |
---|
146 | - if (ga_init(pw->pw_name, pw->pw_gid) == 0) { |
---|
147 | + if (ga_init(pw) == 0) { |
---|
148 | logit("User %.100s from %.100s not allowed because " |
---|
149 | "not in any group", pw->pw_name, hostname); |
---|
150 | return 0; |
---|
151 | --- a/config.h.in 2009-02-23 01:18:12.000000000 +0100 |
---|
152 | +++ b/config.h.in 2009-02-26 01:14:06.000000000 +0100 |
---|
153 | @@ -71,6 +70,18 @@ |
---|
154 | /* Define if your snprintf is busted */ |
---|
155 | #undef BROKEN_SNPRINTF |
---|
156 | |
---|
157 | +/* platform uses an in-memory credentials cache */ |
---|
158 | +#undef USE_CCAPI |
---|
159 | + |
---|
160 | +/* platform has a Security Authorization Session API */ |
---|
161 | +#undef USE_SECURITY_SESSION_API |
---|
162 | + |
---|
163 | +/* Define to 1 if you have the `copyfile' function. */ |
---|
164 | +#undef HAVE_COPYFILE |
---|
165 | + |
---|
166 | +/* Define to 1 if you have the <copyfile.h> header file. */ |
---|
167 | +#undef HAVE_COPYFILE_H |
---|
168 | + |
---|
169 | /* tcgetattr with ICANON may hang */ |
---|
170 | #undef BROKEN_TCGETATTR_ICANON |
---|
171 | |
---|
172 | --- a/configure.ac 2009-02-16 05:37:03.000000000 +0100 |
---|
173 | +++ b/configure.ac 2009-02-26 01:14:06.000000000 +0100 |
---|
174 | @@ -4197,10 +4221,40 @@ |
---|
175 | AC_MSG_WARN([Please check and edit blibpath in LDFLAGS in Makefile]) |
---|
176 | fi |
---|
177 | |
---|
178 | +dnl Keychain support |
---|
179 | +AC_ARG_WITH(keychain, |
---|
180 | + [ --with-keychain=apple Use Mac OS X Keychain], |
---|
181 | + [ |
---|
182 | + case "$withval" in |
---|
183 | + apple|no) |
---|
184 | + KEYCHAIN=$withval |
---|
185 | + ;; |
---|
186 | + *) |
---|
187 | + AC_MSG_ERROR(invalid keychain type: $withval) |
---|
188 | + ;; |
---|
189 | + esac |
---|
190 | + ] |
---|
191 | +) |
---|
192 | +if test ! -z "$KEYCHAIN" -a "$KEYCHAIN" != "no"; then |
---|
193 | + case "$KEYCHAIN" in |
---|
194 | + apple) |
---|
195 | + AC_CHECK_HEADERS(Security/Security.h, [ |
---|
196 | + CPPFLAGS="$CPPFLAGS -D__APPLE_KEYCHAIN__" |
---|
197 | + KEYCHAIN_LDFLAGS="-framework Security -framework CoreFoundation" |
---|
198 | + AC_SUBST(KEYCHAIN_LDFLAGS) |
---|
199 | + ], |
---|
200 | + AC_MSG_WARN([Security framework not found. Disabling Mac OS X Keychain support.])) |
---|
201 | + ;; |
---|
202 | + esac |
---|
203 | +fi |
---|
204 | + |
---|
205 | dnl Adding -Werror to CFLAGS early prevents configure tests from running. |
---|
206 | dnl Add now. |
---|
207 | CFLAGS="$CFLAGS $werror_flags" |
---|
208 | |
---|
209 | +AC_CHECK_FUNCS(copyfile) |
---|
210 | +AC_CHECK_HEADERS(copyfile.h) |
---|
211 | + |
---|
212 | if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then |
---|
213 | TEST_SSH_IPV6=no |
---|
214 | else |
---|
215 | --- a/groupaccess.c 2008-07-04 05:51:12.000000000 +0200 |
---|
216 | +++ b/groupaccess.c 2008-08-23 00:38:21.000000000 +0200 |
---|
217 | @@ -33,38 +33,67 @@ |
---|
218 | #include <stdarg.h> |
---|
219 | #include <string.h> |
---|
220 | |
---|
221 | +#ifdef __APPLE_MEMBERSHIP__ |
---|
222 | +#include <membership.h> |
---|
223 | +#endif |
---|
224 | + |
---|
225 | #include "xmalloc.h" |
---|
226 | #include "groupaccess.h" |
---|
227 | #include "match.h" |
---|
228 | #include "log.h" |
---|
229 | |
---|
230 | +#ifdef __APPLE_MEMBERSHIP__ |
---|
231 | +// SPI for 5235093 |
---|
232 | +int32_t getgrouplist_2(const char *, gid_t, gid_t **); |
---|
233 | +int32_t getgroupcount(const char *, gid_t); |
---|
234 | +#endif |
---|
235 | + |
---|
236 | static int ngroups; |
---|
237 | static char **groups_byname; |
---|
238 | +#ifdef __APPLE_MEMBERSHIP__ |
---|
239 | +uuid_t u_uuid; |
---|
240 | +#endif |
---|
241 | |
---|
242 | /* |
---|
243 | * Initialize group access list for user with primary (base) and |
---|
244 | * supplementary groups. Return the number of groups in the list. |
---|
245 | */ |
---|
246 | int |
---|
247 | -ga_init(const char *user, gid_t base) |
---|
248 | +ga_init(struct passwd *pw) |
---|
249 | { |
---|
250 | - gid_t *groups_bygid; |
---|
251 | + gid_t *groups_bygid = NULL; |
---|
252 | int i, j; |
---|
253 | struct group *gr; |
---|
254 | |
---|
255 | +#ifdef __APPLE_MEMBERSHIP__ |
---|
256 | + if (0 != mbr_uid_to_uuid(pw->pw_uid, u_uuid)) |
---|
257 | + return 0; |
---|
258 | +#endif |
---|
259 | + |
---|
260 | if (ngroups > 0) |
---|
261 | ga_free(); |
---|
262 | |
---|
263 | +#ifndef __APPLE_MEMBERSHIP__ |
---|
264 | ngroups = NGROUPS_MAX; |
---|
265 | #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) |
---|
266 | ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX)); |
---|
267 | -#endif |
---|
268 | - |
---|
269 | +#endif |
---|
270 | groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid)); |
---|
271 | +#else |
---|
272 | + if (-1 == (ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid, |
---|
273 | + &groups_bygid))) { |
---|
274 | + logit("getgrouplist_2 failed"); |
---|
275 | + return; |
---|
276 | + } |
---|
277 | +#endif |
---|
278 | groups_byname = xcalloc(ngroups, sizeof(*groups_byname)); |
---|
279 | - |
---|
280 | - if (getgrouplist(user, base, groups_bygid, &ngroups) == -1) |
---|
281 | - logit("getgrouplist: groups list too small"); |
---|
282 | +#ifndef __APPLE_MEMBERSHIP__ |
---|
283 | + if (getgrouplist(pw->pw_name, pw->pw_gid, groups_bygid, &ngroups) == -1) { |
---|
284 | + logit("getgrouplist: groups list too small"); |
---|
285 | + xfree(groups_bygid); |
---|
286 | + return; |
---|
287 | + } |
---|
288 | +#endif |
---|
289 | for (i = 0, j = 0; i < ngroups; i++) |
---|
290 | if ((gr = getgrgid(groups_bygid[i])) != NULL) |
---|
291 | groups_byname[j++] = xstrdup(gr->gr_name); |
---|
292 | @@ -75,16 +104,32 @@ |
---|
293 | /* |
---|
294 | * Return 1 if one of user's groups is contained in groups. |
---|
295 | * Return 0 otherwise. Use match_pattern() for string comparison. |
---|
296 | + * Use mbr_check_membership() for membership checking on Mac OS X. |
---|
297 | */ |
---|
298 | int |
---|
299 | ga_match(char * const *groups, int n) |
---|
300 | { |
---|
301 | +#ifdef __APPLE_MEMBERSHIP__ |
---|
302 | + int i, ismember = 0; |
---|
303 | + uuid_t g_uuid; |
---|
304 | + struct group *grp; |
---|
305 | + |
---|
306 | + for (i = 0; i < n; i++) { |
---|
307 | + if ((grp = getgrnam(groups[i])) == NULL || |
---|
308 | + (mbr_gid_to_uuid(grp->gr_gid, g_uuid) != 0) || |
---|
309 | + (mbr_check_membership(u_uuid, g_uuid, &ismember) != 0)) |
---|
310 | + return 0; |
---|
311 | + if (ismember) |
---|
312 | + return 1; |
---|
313 | + } |
---|
314 | +#else |
---|
315 | int i, j; |
---|
316 | |
---|
317 | for (i = 0; i < ngroups; i++) |
---|
318 | for (j = 0; j < n; j++) |
---|
319 | if (match_pattern(groups_byname[i], groups[j])) |
---|
320 | return 1; |
---|
321 | +#endif |
---|
322 | return 0; |
---|
323 | } |
---|
324 | |
---|
325 | --- a/groupaccess.h 2008-07-04 05:51:12.000000000 +0200 |
---|
326 | +++ b/groupaccess.h 2008-07-29 23:58:20.000000000 +0200 |
---|
327 | @@ -27,7 +27,7 @@ |
---|
328 | #ifndef GROUPACCESS_H |
---|
329 | #define GROUPACCESS_H |
---|
330 | |
---|
331 | -int ga_init(const char *, gid_t); |
---|
332 | +int ga_init(struct passwd *); |
---|
333 | int ga_match(char * const *, int); |
---|
334 | int ga_match_pattern_list(const char *); |
---|
335 | void ga_free(void); |
---|
336 | --- a/keychain.c 1970-01-01 01:00:00.000000000 +0100 |
---|
337 | +++ b/keychain.c 2008-11-15 00:16:08.000000000 +0100 |
---|
338 | @@ -0,0 +1,694 @@ |
---|
339 | +/* |
---|
340 | + * Copyright (c) 2007 Apple Inc. All rights reserved. |
---|
341 | + * |
---|
342 | + * @APPLE_BSD_LICENSE_HEADER_START@ |
---|
343 | + * |
---|
344 | + * Redistribution and use in source and binary forms, with or without |
---|
345 | + * modification, are permitted provided that the following conditions |
---|
346 | + * are met: |
---|
347 | + * |
---|
348 | + * 1. Redistributions of source code must retain the above copyright |
---|
349 | + * notice, this list of conditions and the following disclaimer. |
---|
350 | + * 2. Redistributions in binary form must reproduce the above copyright |
---|
351 | + * notice, this list of conditions and the following disclaimer in the |
---|
352 | + * documentation and/or other materials provided with the distribution. |
---|
353 | + * 3. Neither the name of Apple Inc. ("Apple") nor the names of its |
---|
354 | + * contributors may be used to endorse or promote products derived from |
---|
355 | + * this software without specific prior written permission. |
---|
356 | + * |
---|
357 | + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
---|
358 | + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
---|
359 | + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
---|
360 | + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
---|
361 | + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
---|
362 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
---|
363 | + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
---|
364 | + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
365 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
366 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
367 | + * |
---|
368 | + * @APPLE_BSD_LICENSE_HEADER_END@ |
---|
369 | + */ |
---|
370 | + |
---|
371 | +#include "includes.h" |
---|
372 | + |
---|
373 | +#include <stdio.h> |
---|
374 | +#include <string.h> |
---|
375 | + |
---|
376 | +#include "xmalloc.h" |
---|
377 | +#include "key.h" |
---|
378 | +#include "authfd.h" |
---|
379 | +#include "authfile.h" |
---|
380 | + |
---|
381 | +#if defined(__APPLE_KEYCHAIN__) |
---|
382 | + |
---|
383 | +#include <CoreFoundation/CoreFoundation.h> |
---|
384 | +#include <Security/Security.h> |
---|
385 | + |
---|
386 | +/* Our Security/SecPassword.h is not yet API, so I will define the constants that I am using here. */ |
---|
387 | +int kSecPasswordGet = 1<<0; // Get password from keychain or user |
---|
388 | +int kSecPasswordSet = 1<<1; // Set password (passed in if kSecPasswordGet not set, otherwise from user) |
---|
389 | +int kSecPasswordFail = 1<<2; // Wrong password (ignore item in keychain and flag error) |
---|
390 | +OSStatus SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef); |
---|
391 | +OSStatus SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data); |
---|
392 | +OSStatus SecPasswordSetInitialAccess(SecPasswordRef itemRef, SecAccessRef accessRef); |
---|
393 | + |
---|
394 | +#endif |
---|
395 | + |
---|
396 | +/* |
---|
397 | + * Platform-specific helper functions. |
---|
398 | + */ |
---|
399 | + |
---|
400 | +#if defined(__APPLE_KEYCHAIN__) |
---|
401 | + |
---|
402 | +static int get_boolean_preference(const char *key, int default_value, |
---|
403 | + int foreground) |
---|
404 | +{ |
---|
405 | + int value = default_value; |
---|
406 | + CFStringRef keyRef = NULL; |
---|
407 | + CFPropertyListRef valueRef = NULL; |
---|
408 | + |
---|
409 | + keyRef = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8); |
---|
410 | + if (keyRef != NULL) |
---|
411 | + valueRef = CFPreferencesCopyAppValue(keyRef, |
---|
412 | + CFSTR("org.openbsd.openssh")); |
---|
413 | + if (valueRef != NULL) |
---|
414 | + if (CFGetTypeID(valueRef) == CFBooleanGetTypeID()) |
---|
415 | + value = CFBooleanGetValue(valueRef); |
---|
416 | + else if (foreground) |
---|
417 | + fprintf(stderr, "Ignoring nonboolean %s preference.\n", key); |
---|
418 | + |
---|
419 | + if (keyRef) |
---|
420 | + CFRelease(keyRef); |
---|
421 | + if (valueRef) |
---|
422 | + CFRelease(valueRef); |
---|
423 | + |
---|
424 | + return value; |
---|
425 | +} |
---|
426 | + |
---|
427 | +#endif |
---|
428 | + |
---|
429 | +/* |
---|
430 | + * Store the passphrase for a given identity in the keychain. |
---|
431 | + */ |
---|
432 | +void |
---|
433 | +store_in_keychain(const char *filename, const char *passphrase) |
---|
434 | +{ |
---|
435 | + |
---|
436 | +#if defined(__APPLE_KEYCHAIN__) |
---|
437 | + |
---|
438 | + /* |
---|
439 | + * store_in_keychain |
---|
440 | + * Mac OS X implementation |
---|
441 | + */ |
---|
442 | + |
---|
443 | + CFStringRef cfstr_relative_filename = NULL; |
---|
444 | + CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL; |
---|
445 | + CFStringRef cfstr_filename = NULL; |
---|
446 | + CFDataRef cfdata_filename = NULL; |
---|
447 | + CFIndex filename_len; |
---|
448 | + UInt8 *label = NULL; |
---|
449 | + UInt8 *utf8_filename; |
---|
450 | + OSStatus rv; |
---|
451 | + SecKeychainItemRef itemRef = NULL; |
---|
452 | + SecTrustedApplicationRef apps[] = {NULL, NULL, NULL}; |
---|
453 | + CFArrayRef trustedlist = NULL; |
---|
454 | + SecAccessRef initialAccess = NULL; |
---|
455 | + |
---|
456 | + /* Bail out if KeychainIntegration preference is -bool NO */ |
---|
457 | + if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) { |
---|
458 | + fprintf(stderr, "Keychain integration is disabled.\n"); |
---|
459 | + goto err; |
---|
460 | + } |
---|
461 | + |
---|
462 | + /* Interpret filename with the correct encoding. */ |
---|
463 | + if ((cfstr_relative_filename = |
---|
464 | + CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL) |
---|
465 | + { |
---|
466 | + fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n"); |
---|
467 | + goto err; |
---|
468 | + } |
---|
469 | + if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL, |
---|
470 | + cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) { |
---|
471 | + fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n"); |
---|
472 | + goto err; |
---|
473 | + } |
---|
474 | + if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) == |
---|
475 | + NULL) { |
---|
476 | + fprintf(stderr, "CFURLCopyAbsoluteURL failed\n"); |
---|
477 | + goto err; |
---|
478 | + } |
---|
479 | + if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename, |
---|
480 | + kCFURLPOSIXPathStyle)) == NULL) { |
---|
481 | + fprintf(stderr, "CFURLCopyFileSystemPath failed\n"); |
---|
482 | + goto err; |
---|
483 | + } |
---|
484 | + if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL, |
---|
485 | + cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) { |
---|
486 | + fprintf(stderr, "CFStringCreateExternalRepresentation failed\n"); |
---|
487 | + goto err; |
---|
488 | + } |
---|
489 | + filename_len = CFDataGetLength(cfdata_filename); |
---|
490 | + if ((label = xmalloc(filename_len + 5)) == NULL) { |
---|
491 | + fprintf(stderr, "xmalloc failed\n"); |
---|
492 | + goto err; |
---|
493 | + } |
---|
494 | + memcpy(label, "SSH: ", 5); |
---|
495 | + utf8_filename = label + 5; |
---|
496 | + CFDataGetBytes(cfdata_filename, CFRangeMake(0, filename_len), |
---|
497 | + utf8_filename); |
---|
498 | + |
---|
499 | + /* Check if we already have this passphrase. */ |
---|
500 | + rv = SecKeychainFindGenericPassword(NULL, 3, "SSH", filename_len, |
---|
501 | + (char *)utf8_filename, NULL, NULL, &itemRef); |
---|
502 | + if (rv == errSecItemNotFound) { |
---|
503 | + /* Add a new keychain item. */ |
---|
504 | + SecKeychainAttribute attrs[] = { |
---|
505 | + {kSecLabelItemAttr, filename_len + 5, label}, |
---|
506 | + {kSecServiceItemAttr, 3, "SSH"}, |
---|
507 | + {kSecAccountItemAttr, filename_len, utf8_filename} |
---|
508 | + }; |
---|
509 | + SecKeychainAttributeList attrList = |
---|
510 | + {sizeof(attrs) / sizeof(attrs[0]), attrs}; |
---|
511 | + if (SecTrustedApplicationCreateFromPath("/usr/bin/ssh-agent", |
---|
512 | + &apps[0]) != noErr || |
---|
513 | + SecTrustedApplicationCreateFromPath("/usr/bin/ssh-add", |
---|
514 | + &apps[1]) != noErr || |
---|
515 | + SecTrustedApplicationCreateFromPath("/usr/bin/ssh", |
---|
516 | + &apps[2]) != noErr) { |
---|
517 | + fprintf(stderr, "SecTrustedApplicationCreateFromPath failed\n"); |
---|
518 | + goto err; |
---|
519 | + } |
---|
520 | + if ((trustedlist = CFArrayCreate(NULL, (const void **)apps, |
---|
521 | + sizeof(apps) / sizeof(apps[0]), &kCFTypeArrayCallBacks)) == |
---|
522 | + NULL) { |
---|
523 | + fprintf(stderr, "CFArrayCreate failed\n"); |
---|
524 | + goto err; |
---|
525 | + } |
---|
526 | + if (SecAccessCreate(cfstr_filename, trustedlist, |
---|
527 | + &initialAccess) != noErr) { |
---|
528 | + fprintf(stderr, "SecAccessCreate failed\n"); |
---|
529 | + goto err; |
---|
530 | + } |
---|
531 | + if (SecKeychainItemCreateFromContent( |
---|
532 | + kSecGenericPasswordItemClass, &attrList, strlen(passphrase), |
---|
533 | + passphrase, NULL, initialAccess, NULL) == noErr) |
---|
534 | + fprintf(stderr, "Passphrase stored in keychain: %s\n", filename); |
---|
535 | + else |
---|
536 | + fprintf(stderr, "Could not create keychain item\n"); |
---|
537 | + } else if (rv == noErr) { |
---|
538 | + /* Update an existing keychain item. */ |
---|
539 | + if (SecKeychainItemModifyAttributesAndData(itemRef, NULL, |
---|
540 | + strlen(passphrase), passphrase) == noErr) |
---|
541 | + fprintf(stderr, "Passphrase updated in keychain: %s\n", filename); |
---|
542 | + else |
---|
543 | + fprintf(stderr, "Could not modify keychain item\n"); |
---|
544 | + } else |
---|
545 | + fprintf(stderr, "Could not access keychain\n"); |
---|
546 | + |
---|
547 | +err: /* Clean up. */ |
---|
548 | + if (cfstr_relative_filename) |
---|
549 | + CFRelease(cfstr_relative_filename); |
---|
550 | + if (cfurl_relative_filename) |
---|
551 | + CFRelease(cfurl_relative_filename); |
---|
552 | + if (cfurl_filename) |
---|
553 | + CFRelease(cfurl_filename); |
---|
554 | + if (cfstr_filename) |
---|
555 | + CFRelease(cfstr_filename); |
---|
556 | + if (cfdata_filename) |
---|
557 | + CFRelease(cfdata_filename); |
---|
558 | + if (label) |
---|
559 | + xfree(label); |
---|
560 | + if (itemRef) |
---|
561 | + CFRelease(itemRef); |
---|
562 | + if (apps[0]) |
---|
563 | + CFRelease(apps[0]); |
---|
564 | + if (apps[1]) |
---|
565 | + CFRelease(apps[1]); |
---|
566 | + if (apps[2]) |
---|
567 | + CFRelease(apps[2]); |
---|
568 | + if (trustedlist) |
---|
569 | + CFRelease(trustedlist); |
---|
570 | + if (initialAccess) |
---|
571 | + CFRelease(initialAccess); |
---|
572 | + |
---|
573 | +#else |
---|
574 | + |
---|
575 | + /* |
---|
576 | + * store_in_keychain |
---|
577 | + * no keychain implementation |
---|
578 | + */ |
---|
579 | + |
---|
580 | + fprintf(stderr, "Keychain is not available on this system\n"); |
---|
581 | + |
---|
582 | +#endif |
---|
583 | + |
---|
584 | +} |
---|
585 | + |
---|
586 | +/* |
---|
587 | + * Remove the passphrase for a given identity from the keychain. |
---|
588 | + */ |
---|
589 | +void |
---|
590 | +remove_from_keychain(const char *filename) |
---|
591 | +{ |
---|
592 | + |
---|
593 | +#if defined(__APPLE_KEYCHAIN__) |
---|
594 | + |
---|
595 | + /* |
---|
596 | + * remove_from_keychain |
---|
597 | + * Mac OS X implementation |
---|
598 | + */ |
---|
599 | + |
---|
600 | + CFStringRef cfstr_relative_filename = NULL; |
---|
601 | + CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL; |
---|
602 | + CFStringRef cfstr_filename = NULL; |
---|
603 | + CFDataRef cfdata_filename = NULL; |
---|
604 | + CFIndex filename_len; |
---|
605 | + const UInt8 *utf8_filename; |
---|
606 | + OSStatus rv; |
---|
607 | + SecKeychainItemRef itemRef = NULL; |
---|
608 | + |
---|
609 | + /* Bail out if KeychainIntegration preference is -bool NO */ |
---|
610 | + if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) { |
---|
611 | + fprintf(stderr, "Keychain integration is disabled.\n"); |
---|
612 | + goto err; |
---|
613 | + } |
---|
614 | + |
---|
615 | + /* Interpret filename with the correct encoding. */ |
---|
616 | + if ((cfstr_relative_filename = |
---|
617 | + CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL) |
---|
618 | + { |
---|
619 | + fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n"); |
---|
620 | + goto err; |
---|
621 | + } |
---|
622 | + if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL, |
---|
623 | + cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) { |
---|
624 | + fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n"); |
---|
625 | + goto err; |
---|
626 | + } |
---|
627 | + if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) == |
---|
628 | + NULL) { |
---|
629 | + fprintf(stderr, "CFURLCopyAbsoluteURL failed\n"); |
---|
630 | + goto err; |
---|
631 | + } |
---|
632 | + if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename, |
---|
633 | + kCFURLPOSIXPathStyle)) == NULL) { |
---|
634 | + fprintf(stderr, "CFURLCopyFileSystemPath failed\n"); |
---|
635 | + goto err; |
---|
636 | + } |
---|
637 | + if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL, |
---|
638 | + cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) { |
---|
639 | + fprintf(stderr, "CFStringCreateExternalRepresentation failed\n"); |
---|
640 | + goto err; |
---|
641 | + } |
---|
642 | + filename_len = CFDataGetLength(cfdata_filename); |
---|
643 | + utf8_filename = CFDataGetBytePtr(cfdata_filename); |
---|
644 | + |
---|
645 | + /* Check if we already have this passphrase. */ |
---|
646 | + rv = SecKeychainFindGenericPassword(NULL, 3, "SSH", filename_len, |
---|
647 | + (const char *)utf8_filename, NULL, NULL, &itemRef); |
---|
648 | + if (rv == noErr) { |
---|
649 | + /* Remove the passphrase from the keychain. */ |
---|
650 | + if (SecKeychainItemDelete(itemRef) == noErr) |
---|
651 | + fprintf(stderr, "Passphrase removed from keychain: %s\n", filename); |
---|
652 | + else |
---|
653 | + fprintf(stderr, "Could not remove keychain item\n"); |
---|
654 | + } else if (rv != errSecItemNotFound) |
---|
655 | + fprintf(stderr, "Could not access keychain\n"); |
---|
656 | + |
---|
657 | +err: /* Clean up. */ |
---|
658 | + if (cfstr_relative_filename) |
---|
659 | + CFRelease(cfstr_relative_filename); |
---|
660 | + if (cfurl_relative_filename) |
---|
661 | + CFRelease(cfurl_relative_filename); |
---|
662 | + if (cfurl_filename) |
---|
663 | + CFRelease(cfurl_filename); |
---|
664 | + if (cfstr_filename) |
---|
665 | + CFRelease(cfstr_filename); |
---|
666 | + if (cfdata_filename) |
---|
667 | + CFRelease(cfdata_filename); |
---|
668 | + if (itemRef) |
---|
669 | + CFRelease(itemRef); |
---|
670 | + |
---|
671 | +#else |
---|
672 | + |
---|
673 | + /* |
---|
674 | + * remove_from_keychain |
---|
675 | + * no keychain implementation |
---|
676 | + */ |
---|
677 | + |
---|
678 | + fprintf(stderr, "Keychain is not available on this system\n"); |
---|
679 | + |
---|
680 | +#endif |
---|
681 | + |
---|
682 | +} |
---|
683 | + |
---|
684 | +/* |
---|
685 | + * Add identities to ssh-agent using passphrases stored in the keychain. |
---|
686 | + * Returns zero on success and nonzero on failure. |
---|
687 | + * add_identity is a callback into ssh-agent. It takes a filename and a |
---|
688 | + * passphrase, and attempts to add the identity to the agent. It returns |
---|
689 | + * zero on success and nonzero on failure. |
---|
690 | + */ |
---|
691 | +int |
---|
692 | +add_identities_using_keychain(int (*add_identity)(const char *, const char *)) |
---|
693 | +{ |
---|
694 | + |
---|
695 | +#if defined(__APPLE_KEYCHAIN__) |
---|
696 | + |
---|
697 | + /* |
---|
698 | + * add_identities_using_keychain |
---|
699 | + * Mac OS X implementation |
---|
700 | + */ |
---|
701 | + |
---|
702 | + OSStatus rv; |
---|
703 | + SecKeychainSearchRef searchRef; |
---|
704 | + SecKeychainItemRef itemRef; |
---|
705 | + UInt32 length; |
---|
706 | + void *data; |
---|
707 | + CFIndex maxsize; |
---|
708 | + |
---|
709 | + /* Bail out if KeychainIntegration preference is -bool NO */ |
---|
710 | + if (get_boolean_preference("KeychainIntegration", 1, 0) == 0) |
---|
711 | + return 0; |
---|
712 | + |
---|
713 | + /* Search for SSH passphrases in the keychain */ |
---|
714 | + SecKeychainAttribute attrs[] = { |
---|
715 | + {kSecServiceItemAttr, 3, "SSH"} |
---|
716 | + }; |
---|
717 | + SecKeychainAttributeList attrList = |
---|
718 | + {sizeof(attrs) / sizeof(attrs[0]), attrs}; |
---|
719 | + if ((rv = SecKeychainSearchCreateFromAttributes(NULL, |
---|
720 | + kSecGenericPasswordItemClass, &attrList, &searchRef)) != noErr) |
---|
721 | + return 0; |
---|
722 | + |
---|
723 | + /* Iterate through the search results. */ |
---|
724 | + while ((rv = SecKeychainSearchCopyNext(searchRef, &itemRef)) == noErr) { |
---|
725 | + UInt32 tag = kSecAccountItemAttr; |
---|
726 | + UInt32 format = kSecFormatUnknown; |
---|
727 | + SecKeychainAttributeInfo info = {1, &tag, &format}; |
---|
728 | + SecKeychainAttributeList *itemAttrList = NULL; |
---|
729 | + CFStringRef cfstr_filename = NULL; |
---|
730 | + char *filename = NULL; |
---|
731 | + char *passphrase = NULL; |
---|
732 | + |
---|
733 | + /* Retrieve filename and passphrase. */ |
---|
734 | + if ((rv = SecKeychainItemCopyAttributesAndData(itemRef, &info, |
---|
735 | + NULL, &itemAttrList, &length, &data)) != noErr) |
---|
736 | + goto err; |
---|
737 | + if (itemAttrList->count != 1) |
---|
738 | + goto err; |
---|
739 | + cfstr_filename = CFStringCreateWithBytes(NULL, |
---|
740 | + itemAttrList->attr->data, itemAttrList->attr->length, |
---|
741 | + kCFStringEncodingUTF8, true); |
---|
742 | + maxsize = CFStringGetMaximumSizeOfFileSystemRepresentation( |
---|
743 | + cfstr_filename); |
---|
744 | + if ((filename = xmalloc(maxsize)) == NULL) |
---|
745 | + goto err; |
---|
746 | + if (CFStringGetFileSystemRepresentation(cfstr_filename, |
---|
747 | + filename, maxsize) == false) |
---|
748 | + goto err; |
---|
749 | + if ((passphrase = xmalloc(length + 1)) == NULL) |
---|
750 | + goto err; |
---|
751 | + memcpy(passphrase, data, length); |
---|
752 | + passphrase[length] = '\0'; |
---|
753 | + |
---|
754 | + /* Add the identity. */ |
---|
755 | + add_identity(filename, passphrase); |
---|
756 | + |
---|
757 | +err: /* Clean up. */ |
---|
758 | + if (itemRef) |
---|
759 | + CFRelease(itemRef); |
---|
760 | + if (cfstr_filename) |
---|
761 | + CFRelease(cfstr_filename); |
---|
762 | + if (filename) |
---|
763 | + xfree(filename); |
---|
764 | + if (passphrase) |
---|
765 | + xfree(passphrase); |
---|
766 | + if (itemAttrList) |
---|
767 | + SecKeychainItemFreeAttributesAndData(itemAttrList, |
---|
768 | + data); |
---|
769 | + } |
---|
770 | + |
---|
771 | + CFRelease(searchRef); |
---|
772 | + |
---|
773 | + return 0; |
---|
774 | + |
---|
775 | +#else |
---|
776 | + |
---|
777 | + /* |
---|
778 | + * add_identities_using_keychain |
---|
779 | + * no implementation |
---|
780 | + */ |
---|
781 | + |
---|
782 | + return 1; |
---|
783 | + |
---|
784 | +#endif |
---|
785 | + |
---|
786 | +} |
---|
787 | + |
---|
788 | +/* |
---|
789 | + * Prompt the user for a key's passphrase. The user will be offered the option |
---|
790 | + * of storing the passphrase in their keychain. Returns the passphrase |
---|
791 | + * (which the caller is responsible for xfreeing), or NULL if this function |
---|
792 | + * fails or is not implemented. If this function is not implemented, ssh will |
---|
793 | + * fall back on the standard read_passphrase function, and the user will need |
---|
794 | + * to use ssh-add -K to add their keys to the keychain. |
---|
795 | + */ |
---|
796 | +char * |
---|
797 | +keychain_read_passphrase(const char *filename, int oAskPassGUI) |
---|
798 | +{ |
---|
799 | + |
---|
800 | +#if defined(__APPLE_KEYCHAIN__) |
---|
801 | + |
---|
802 | + /* |
---|
803 | + * keychain_read_passphrase |
---|
804 | + * Mac OS X implementation |
---|
805 | + */ |
---|
806 | + |
---|
807 | + CFStringRef cfstr_relative_filename = NULL; |
---|
808 | + CFURLRef cfurl_relative_filename = NULL, cfurl_filename = NULL; |
---|
809 | + CFStringRef cfstr_filename = NULL; |
---|
810 | + CFDataRef cfdata_filename = NULL; |
---|
811 | + CFIndex filename_len; |
---|
812 | + UInt8 *label = NULL; |
---|
813 | + UInt8 *utf8_filename; |
---|
814 | + SecPasswordRef passRef = NULL; |
---|
815 | + SecTrustedApplicationRef apps[] = {NULL, NULL, NULL}; |
---|
816 | + CFArrayRef trustedlist = NULL; |
---|
817 | + SecAccessRef initialAccess = NULL; |
---|
818 | + CFURLRef path = NULL; |
---|
819 | + CFStringRef pathFinal = NULL; |
---|
820 | + CFURLRef bundle_url = NULL; |
---|
821 | + CFBundleRef bundle = NULL; |
---|
822 | + CFStringRef promptTemplate = NULL, prompt = NULL; |
---|
823 | + UInt32 length; |
---|
824 | + const void *data; |
---|
825 | + AuthenticationConnection *ac = NULL; |
---|
826 | + char *result = NULL; |
---|
827 | + |
---|
828 | + /* Bail out if KeychainIntegration preference is -bool NO */ |
---|
829 | + if (get_boolean_preference("KeychainIntegration", 1, 1) == 0) |
---|
830 | + goto err; |
---|
831 | + |
---|
832 | + /* Bail out if the user set AskPassGUI preference to -bool NO */ |
---|
833 | + if (get_boolean_preference("AskPassGUI", 1, 1) == 0 || oAskPassGUI == 0) |
---|
834 | + goto err; |
---|
835 | + |
---|
836 | + /* Bail out if we can't communicate with ssh-agent */ |
---|
837 | + if ((ac = ssh_get_authentication_connection()) == NULL) |
---|
838 | + goto err; |
---|
839 | + |
---|
840 | + /* Interpret filename with the correct encoding. */ |
---|
841 | + if ((cfstr_relative_filename = |
---|
842 | + CFStringCreateWithFileSystemRepresentation(NULL, filename)) == NULL) |
---|
843 | + { |
---|
844 | + fprintf(stderr, "CFStringCreateWithFileSystemRepresentation failed\n"); |
---|
845 | + goto err; |
---|
846 | + } |
---|
847 | + if ((cfurl_relative_filename = CFURLCreateWithFileSystemPath(NULL, |
---|
848 | + cfstr_relative_filename, kCFURLPOSIXPathStyle, false)) == NULL) { |
---|
849 | + fprintf(stderr, "CFURLCreateWithFileSystemPath failed\n"); |
---|
850 | + goto err; |
---|
851 | + } |
---|
852 | + if ((cfurl_filename = CFURLCopyAbsoluteURL(cfurl_relative_filename)) == |
---|
853 | + NULL) { |
---|
854 | + fprintf(stderr, "CFURLCopyAbsoluteURL failed\n"); |
---|
855 | + goto err; |
---|
856 | + } |
---|
857 | + if ((cfstr_filename = CFURLCopyFileSystemPath(cfurl_filename, |
---|
858 | + kCFURLPOSIXPathStyle)) == NULL) { |
---|
859 | + fprintf(stderr, "CFURLCopyFileSystemPath failed\n"); |
---|
860 | + goto err; |
---|
861 | + } |
---|
862 | + if ((cfdata_filename = CFStringCreateExternalRepresentation(NULL, |
---|
863 | + cfstr_filename, kCFStringEncodingUTF8, 0)) == NULL) { |
---|
864 | + fprintf(stderr, "CFStringCreateExternalRepresentation failed\n"); |
---|
865 | + goto err; |
---|
866 | + } |
---|
867 | + filename_len = CFDataGetLength(cfdata_filename); |
---|
868 | + if ((label = xmalloc(filename_len + 5)) == NULL) { |
---|
869 | + fprintf(stderr, "xmalloc failed\n"); |
---|
870 | + goto err; |
---|
871 | + } |
---|
872 | + memcpy(label, "SSH: ", 5); |
---|
873 | + utf8_filename = label + 5; |
---|
874 | + CFDataGetBytes(cfdata_filename, CFRangeMake(0, filename_len), |
---|
875 | + utf8_filename); |
---|
876 | + |
---|
877 | + /* Build a SecPasswordRef. */ |
---|
878 | + SecKeychainAttribute searchAttrs[] = { |
---|
879 | + {kSecServiceItemAttr, 3, "SSH"}, |
---|
880 | + {kSecAccountItemAttr, filename_len, utf8_filename} |
---|
881 | + }; |
---|
882 | + SecKeychainAttributeList searchAttrList = |
---|
883 | + {sizeof(searchAttrs) / sizeof(searchAttrs[0]), searchAttrs}; |
---|
884 | + SecKeychainAttribute attrs[] = { |
---|
885 | + {kSecLabelItemAttr, filename_len + 5, label}, |
---|
886 | + {kSecServiceItemAttr, 3, "SSH"}, |
---|
887 | + {kSecAccountItemAttr, filename_len, utf8_filename} |
---|
888 | + }; |
---|
889 | + SecKeychainAttributeList attrList = |
---|
890 | + {sizeof(attrs) / sizeof(attrs[0]), attrs}; |
---|
891 | + if (SecGenericPasswordCreate(&searchAttrList, &attrList, &passRef) != |
---|
892 | + noErr) { |
---|
893 | + fprintf(stderr, "SecGenericPasswordCreate failed\n"); |
---|
894 | + goto err; |
---|
895 | + } |
---|
896 | + if (SecTrustedApplicationCreateFromPath("/usr/bin/ssh-agent", &apps[0]) |
---|
897 | + != noErr || |
---|
898 | + SecTrustedApplicationCreateFromPath("/usr/bin/ssh-add", &apps[1]) |
---|
899 | + != noErr || |
---|
900 | + SecTrustedApplicationCreateFromPath("/usr/bin/ssh", &apps[2]) |
---|
901 | + != noErr) { |
---|
902 | + fprintf(stderr, "SecTrustedApplicationCreateFromPath failed\n"); |
---|
903 | + goto err; |
---|
904 | + } |
---|
905 | + if ((trustedlist = CFArrayCreate(NULL, (const void **)apps, |
---|
906 | + sizeof(apps) / sizeof(apps[0]), &kCFTypeArrayCallBacks)) == NULL) { |
---|
907 | + fprintf(stderr, "CFArrayCreate failed\n"); |
---|
908 | + goto err; |
---|
909 | + } |
---|
910 | + if (SecAccessCreate(cfstr_filename, trustedlist, &initialAccess) |
---|
911 | + != noErr) { |
---|
912 | + fprintf(stderr, "SecAccessCreate failed\n"); |
---|
913 | + goto err; |
---|
914 | + } |
---|
915 | + if (SecPasswordSetInitialAccess(passRef, initialAccess) != noErr) { |
---|
916 | + fprintf(stderr, "SecPasswordSetInitialAccess failed\n"); |
---|
917 | + goto err; |
---|
918 | + } |
---|
919 | + |
---|
920 | + /* Request the passphrase from the user. */ |
---|
921 | + if ((path = CFURLCreateFromFileSystemRepresentation(NULL, |
---|
922 | + (UInt8 *)filename, strlen(filename), false)) == NULL) { |
---|
923 | + fprintf(stderr, "CFURLCreateFromFileSystemRepresentation failed\n"); |
---|
924 | + goto err; |
---|
925 | + } |
---|
926 | + if ((pathFinal = CFURLCopyLastPathComponent(path)) == NULL) { |
---|
927 | + fprintf(stderr, "CFURLCopyLastPathComponent failed\n"); |
---|
928 | + goto err; |
---|
929 | + } |
---|
930 | + if (!((bundle_url = CFURLCreateWithFileSystemPath(NULL, |
---|
931 | + CFSTR("/System/Library/CoreServices/"), kCFURLPOSIXPathStyle, true)) |
---|
932 | + != NULL && (bundle = CFBundleCreate(NULL, bundle_url)) != NULL && |
---|
933 | + (promptTemplate = CFCopyLocalizedStringFromTableInBundle( |
---|
934 | + CFSTR("Enter your password for the SSH key \"%@\"."), |
---|
935 | + CFSTR("OpenSSH"), bundle, "Text of the dialog asking the user for" |
---|
936 | + "their passphrase. The %@ will be replaced with the filename of a" |
---|
937 | + "specific key.")) != NULL) && |
---|
938 | + (promptTemplate = CFStringCreateCopy(NULL, |
---|
939 | + CFSTR("Enter your password for the SSH key \"%@\"."))) == NULL) { |
---|
940 | + fprintf(stderr, "CFStringCreateCopy failed\n"); |
---|
941 | + goto err; |
---|
942 | + } |
---|
943 | + if ((prompt = CFStringCreateWithFormat(NULL, NULL, promptTemplate, |
---|
944 | + pathFinal)) == NULL) { |
---|
945 | + fprintf(stderr, "CFStringCreateWithFormat failed\n"); |
---|
946 | + goto err; |
---|
947 | + } |
---|
948 | + switch (SecPasswordAction(passRef, prompt, |
---|
949 | + kSecPasswordGet|kSecPasswordFail, &length, &data)) { |
---|
950 | + case noErr: |
---|
951 | + result = xmalloc(length + 1); |
---|
952 | + memcpy(result, data, length); |
---|
953 | + result[length] = '\0'; |
---|
954 | + |
---|
955 | + /* Save password in keychain if requested. */ |
---|
956 | + if (noErr != SecPasswordAction(passRef, CFSTR(""), kSecPasswordSet, &length, &data)) |
---|
957 | + fprintf(stderr, "Saving password to keychain failed\n"); |
---|
958 | + |
---|
959 | + /* Add password to agent. */ |
---|
960 | + char *comment = NULL; |
---|
961 | + Key *private = key_load_private(filename, result, &comment); |
---|
962 | + if (NULL == private) |
---|
963 | + break; |
---|
964 | + if (ssh_add_identity_constrained(ac, private, comment, 0, 0)) |
---|
965 | + fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); |
---|
966 | + else |
---|
967 | + fprintf(stderr, "Could not add identity: %s\n", filename); |
---|
968 | + xfree(comment); |
---|
969 | + key_free(private); |
---|
970 | + break; |
---|
971 | + case errAuthorizationCanceled: |
---|
972 | + result = xmalloc(1); |
---|
973 | + *result = '\0'; |
---|
974 | + break; |
---|
975 | + default: |
---|
976 | + goto err; |
---|
977 | + } |
---|
978 | + |
---|
979 | +err: /* Clean up. */ |
---|
980 | + if (cfstr_relative_filename) |
---|
981 | + CFRelease(cfstr_relative_filename); |
---|
982 | + if (cfurl_relative_filename) |
---|
983 | + CFRelease(cfurl_relative_filename); |
---|
984 | + if (cfurl_filename) |
---|
985 | + CFRelease(cfurl_filename); |
---|
986 | + if (cfstr_filename) |
---|
987 | + CFRelease(cfstr_filename); |
---|
988 | + if (cfdata_filename) |
---|
989 | + CFRelease(cfdata_filename); |
---|
990 | + if (label) |
---|
991 | + xfree(label); |
---|
992 | + if (passRef) |
---|
993 | + CFRelease(passRef); |
---|
994 | + if (apps[0]) |
---|
995 | + CFRelease(apps[0]); |
---|
996 | + if (apps[1]) |
---|
997 | + CFRelease(apps[1]); |
---|
998 | + if (apps[2]) |
---|
999 | + CFRelease(apps[2]); |
---|
1000 | + if (trustedlist) |
---|
1001 | + CFRelease(trustedlist); |
---|
1002 | + if (initialAccess) |
---|
1003 | + CFRelease(initialAccess); |
---|
1004 | + if (path) |
---|
1005 | + CFRelease(path); |
---|
1006 | + if (pathFinal) |
---|
1007 | + CFRelease(pathFinal); |
---|
1008 | + if (bundle_url) |
---|
1009 | + CFRelease(bundle_url); |
---|
1010 | + if (bundle) |
---|
1011 | + CFRelease(bundle); |
---|
1012 | + if (promptTemplate) |
---|
1013 | + CFRelease(promptTemplate); |
---|
1014 | + if (prompt) |
---|
1015 | + CFRelease(prompt); |
---|
1016 | + if (ac) |
---|
1017 | + ssh_close_authentication_connection(ac); |
---|
1018 | + |
---|
1019 | + return result; |
---|
1020 | + |
---|
1021 | +#else |
---|
1022 | + |
---|
1023 | + /* |
---|
1024 | + * keychain_read_passphrase |
---|
1025 | + * no implementation |
---|
1026 | + */ |
---|
1027 | + |
---|
1028 | + return NULL; |
---|
1029 | + |
---|
1030 | +#endif |
---|
1031 | + |
---|
1032 | +} |
---|
1033 | --- a/keychain.h 1970-01-01 01:00:00.000000000 +0100 |
---|
1034 | +++ b/keychain.h 2008-10-09 01:55:13.000000000 +0200 |
---|
1035 | @@ -0,0 +1,45 @@ |
---|
1036 | +/* |
---|
1037 | + * Copyright (c) 2007 Apple Inc. All rights reserved. |
---|
1038 | + * |
---|
1039 | + * @APPLE_BSD_LICENSE_HEADER_START@ |
---|
1040 | + * |
---|
1041 | + * Redistribution and use in source and binary forms, with or without |
---|
1042 | + * modification, are permitted provided that the following conditions |
---|
1043 | + * are met: |
---|
1044 | + * |
---|
1045 | + * 1. Redistributions of source code must retain the above copyright |
---|
1046 | + * notice, this list of conditions and the following disclaimer. |
---|
1047 | + * 2. Redistributions in binary form must reproduce the above copyright |
---|
1048 | + * notice, this list of conditions and the following disclaimer in the |
---|
1049 | + * documentation and/or other materials provided with the distribution. |
---|
1050 | + * 3. Neither the name of Apple Inc. ("Apple") nor the names of its |
---|
1051 | + * contributors may be used to endorse or promote products derived from |
---|
1052 | + * this software without specific prior written permission. |
---|
1053 | + * |
---|
1054 | + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
---|
1055 | + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
---|
1056 | + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
---|
1057 | + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
---|
1058 | + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
---|
1059 | + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
---|
1060 | + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
---|
1061 | + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
1062 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
1063 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
1064 | + * |
---|
1065 | + * @APPLE_BSD_LICENSE_HEADER_END@ |
---|
1066 | + */ |
---|
1067 | + |
---|
1068 | +/* |
---|
1069 | + * KEYCHAIN indicates that keychain functionality is present. |
---|
1070 | + * KEYCHAIN_* indicates the implementation to use, and implies KEYCHAIN. |
---|
1071 | + */ |
---|
1072 | +#if defined(__APPLE_KEYCHAIN__) |
---|
1073 | +#define KEYCHAIN |
---|
1074 | +#endif |
---|
1075 | + |
---|
1076 | +void store_in_keychain(const char *filename, const char *passphrase); |
---|
1077 | +void remove_from_keychain(const char *filename); |
---|
1078 | +int add_identities_using_keychain( |
---|
1079 | + int (*add_identity)(const char *, const char *)); |
---|
1080 | +char *keychain_read_passphrase(const char *filename, int oAskPassGUI); |
---|
1081 | --- a/readconf.c 2009-02-14 06:28:21.000000000 +0100 |
---|
1082 | +++ b/readconf.c 2009-02-26 01:14:06.000000000 +0100 |
---|
1083 | @@ -137,6 +137,9 @@ |
---|
1084 | oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, |
---|
1085 | oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, |
---|
1086 | oKexAlgorithms, oIPQoS, oRequestTTY, |
---|
1087 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1088 | + oAskPassGUI, |
---|
1089 | +#endif |
---|
1090 | oDeprecated, oUnsupported |
---|
1091 | } OpCodes; |
---|
1092 | |
---|
1093 | @@ -234,7 +243,9 @@ |
---|
1094 | { "kexalgorithms", oKexAlgorithms }, |
---|
1095 | { "ipqos", oIPQoS }, |
---|
1096 | { "requesttty", oRequestTTY }, |
---|
1097 | - |
---|
1098 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1099 | + { "askpassgui", oAskPassGUI }, |
---|
1100 | +#endif |
---|
1101 | { NULL, oBadOption } |
---|
1102 | }; |
---|
1103 | |
---|
1104 | @@ -914,6 +933,12 @@ |
---|
1105 | *intptr = value; |
---|
1106 | break; |
---|
1107 | |
---|
1108 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1109 | + case oAskPassGUI: |
---|
1110 | + intptr = &options->ask_pass_gui; |
---|
1111 | + goto parse_flag; |
---|
1112 | +#endif |
---|
1113 | + |
---|
1114 | case oDeprecated: |
---|
1115 | debug("%s line %d: Deprecated option \"%s\"", |
---|
1116 | filename, linenum, keyword); |
---|
1117 | @@ -1065,6 +1092,9 @@ |
---|
1118 | options->ip_qos_interactive = -1; |
---|
1119 | options->ip_qos_bulk = -1; |
---|
1120 | options->request_tty = -1; |
---|
1121 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1122 | + options->ask_pass_gui = -1; |
---|
1123 | +#endif |
---|
1124 | } |
---|
1125 | |
---|
1126 | /* |
---|
1127 | @@ -1203,6 +1237,10 @@ |
---|
1128 | options->ip_qos_bulk = IPTOS_THROUGHPUT; |
---|
1129 | if (options->request_tty == -1) |
---|
1130 | options->request_tty = REQUEST_TTY_AUTO; |
---|
1131 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1132 | + if (options->ask_pass_gui == -1) |
---|
1133 | + options->ask_pass_gui = 1; |
---|
1134 | +#endif |
---|
1135 | /* options->local_command should not be set by default */ |
---|
1136 | /* options->proxy_command should not be set by default */ |
---|
1137 | /* options->user will be set in the main program if appropriate */ |
---|
1138 | --- a/readconf.h 2009-02-14 06:28:21.000000000 +0100 |
---|
1139 | +++ b/readconf.h 2009-02-26 01:14:06.000000000 +0100 |
---|
1140 | @@ -139,6 +139,10 @@ |
---|
1141 | int use_roaming; |
---|
1142 | |
---|
1143 | int request_tty; |
---|
1144 | + |
---|
1145 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1146 | + int ask_pass_gui; |
---|
1147 | +#endif |
---|
1148 | } Options; |
---|
1149 | |
---|
1150 | #define SSHCTL_MASTER_NO 0 |
---|
1151 | --- a/scp.1 2008-07-12 09:12:49.000000000 +0200 |
---|
1152 | +++ b/scp.1 2008-07-28 19:29:42.000000000 +0200 |
---|
1153 | @@ -20,7 +20,7 @@ |
---|
1154 | .Sh SYNOPSIS |
---|
1155 | .Nm scp |
---|
1156 | .Bk -words |
---|
1157 | -.Op Fl 12346BCpqrv |
---|
1158 | +.Op Fl 12346BCEpqrv |
---|
1159 | .Op Fl c Ar cipher |
---|
1160 | .Op Fl F Ar ssh_config |
---|
1161 | .Op Fl i Ar identity_file |
---|
1162 | @@ -93,6 +93,8 @@ |
---|
1163 | flag to |
---|
1164 | .Xr ssh 1 |
---|
1165 | to enable compression. |
---|
1166 | +.It Fl E |
---|
1167 | +Preserves extended attributes, resource forks, and ACLs. Requires both ends to be running Mac OS X 10.4 or later. |
---|
1168 | .It Fl c Ar cipher |
---|
1169 | Selects the cipher to use for encrypting the data transfer. |
---|
1170 | This option is directly passed to |
---|
1171 | --- a/scp.c 2008-11-03 09:23:45.000000000 +0100 |
---|
1172 | +++ b/scp.c 2009-02-26 01:14:06.000000000 +0100 |
---|
1173 | @@ -78,6 +78,9 @@ |
---|
1174 | #ifdef HAVE_SYS_STAT_H |
---|
1175 | # include <sys/stat.h> |
---|
1176 | #endif |
---|
1177 | +#ifdef __APPLE_XSAN__ |
---|
1178 | +#include <sys/mount.h> |
---|
1179 | +#endif |
---|
1180 | #ifdef HAVE_POLL_H |
---|
1181 | #include <poll.h> |
---|
1182 | #else |
---|
1183 | @@ -114,6 +117,11 @@ |
---|
1184 | #include "misc.h" |
---|
1185 | #include "progressmeter.h" |
---|
1186 | |
---|
1187 | +#ifdef HAVE_COPYFILE_H |
---|
1188 | +#include <libgen.h> |
---|
1189 | +#include <copyfile.h> |
---|
1190 | +#endif |
---|
1191 | + |
---|
1192 | extern char *__progname; |
---|
1193 | |
---|
1194 | #define COPY_BUFLEN 16384 |
---|
1195 | @@ -143,6 +151,12 @@ |
---|
1196 | /* This is used to store the pid of ssh_program */ |
---|
1197 | pid_t do_cmd_pid = -1; |
---|
1198 | |
---|
1199 | +#ifdef HAVE_COPYFILE |
---|
1200 | +int copy_xattr = 0; |
---|
1201 | +int md_flag = 0; |
---|
1202 | +#endif |
---|
1203 | + |
---|
1204 | + |
---|
1205 | static void |
---|
1206 | killchild(int signo) |
---|
1207 | { |
---|
1208 | @@ -323,7 +337,11 @@ |
---|
1209 | addargs(&args, "-oClearAllForwardings yes"); |
---|
1210 | |
---|
1211 | fflag = tflag = 0; |
---|
1212 | +#if HAVE_COPYFILE |
---|
1213 | + while ((ch = getopt(argc, argv, "dfl:prtvBCEc:i:P:q12346S:o:F:")) != -1) |
---|
1214 | +#else |
---|
1215 | while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) |
---|
1216 | +#endif |
---|
1217 | switch (ch) { |
---|
1218 | /* User-visible flags. */ |
---|
1219 | case '1': |
---|
1220 | @@ -369,6 +387,11 @@ |
---|
1221 | showprogress = 0; |
---|
1222 | break; |
---|
1223 | |
---|
1224 | +#ifdef HAVE_COPYFILE |
---|
1225 | + case 'E': |
---|
1226 | + copy_xattr = 1; |
---|
1227 | + break; |
---|
1228 | +#endif |
---|
1229 | /* Server options. */ |
---|
1230 | case 'd': |
---|
1231 | targetshouldbedirectory = 1; |
---|
1232 | @@ -418,7 +441,12 @@ |
---|
1233 | remin = remout = -1; |
---|
1234 | do_cmd_pid = -1; |
---|
1235 | /* Command to be executed on remote system using "ssh". */ |
---|
1236 | +#if HAVE_COPYFILE |
---|
1237 | + (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s%s", |
---|
1238 | + copy_xattr ? " -E" : "", |
---|
1239 | +#else |
---|
1240 | (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", |
---|
1241 | +#endif |
---|
1242 | verbose_mode ? " -v" : "", |
---|
1243 | iamrecursive ? " -r" : "", pflag ? " -p" : "", |
---|
1244 | targetshouldbedirectory ? " -d" : ""); |
---|
1245 | @@ -634,6 +662,10 @@ |
---|
1246 | int fd = -1, haderr, indx; |
---|
1247 | char *last, *name, buf[2048], encname[MAXPATHLEN]; |
---|
1248 | int len; |
---|
1249 | +#if HAVE_COPYFILE |
---|
1250 | + char md_name[MAXPATHLEN]; |
---|
1251 | + char *md_tmp; |
---|
1252 | +#endif |
---|
1253 | |
---|
1254 | for (indx = 0; indx < argc; ++indx) { |
---|
1255 | name = argv[indx]; |
---|
1256 | @@ -641,12 +673,26 @@ |
---|
1257 | len = strlen(name); |
---|
1258 | while (len > 1 && name[len-1] == '/') |
---|
1259 | name[--len] = '\0'; |
---|
1260 | +#if HAVE_COPYFILE |
---|
1261 | +md_next: |
---|
1262 | + statbytes = 0; |
---|
1263 | + if (md_flag) { |
---|
1264 | + fd = open(md_tmp, O_RDONLY, 0); |
---|
1265 | + unlink(md_tmp); |
---|
1266 | + free(md_tmp); |
---|
1267 | + if (fd < 0) |
---|
1268 | + goto syserr; |
---|
1269 | + } else { |
---|
1270 | +#endif |
---|
1271 | if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0) |
---|
1272 | goto syserr; |
---|
1273 | if (strchr(name, '\n') != NULL) { |
---|
1274 | strnvis(encname, name, sizeof(encname), VIS_NL); |
---|
1275 | name = encname; |
---|
1276 | } |
---|
1277 | +#if HAVE_COPYFILE |
---|
1278 | + } |
---|
1279 | +#endif |
---|
1280 | if (fstat(fd, &stb) < 0) { |
---|
1281 | syserr: run_err("%s: %s", name, strerror(errno)); |
---|
1282 | goto next; |
---|
1283 | @@ -743,6 +789,36 @@ |
---|
1284 | else |
---|
1285 | run_err("%s: %s", name, strerror(haderr)); |
---|
1286 | (void) response(); |
---|
1287 | +#ifdef HAVE_COPYFILE |
---|
1288 | + if (copy_xattr && md_flag == 0) |
---|
1289 | + { |
---|
1290 | + if (!copyfile(name, NULL, 0, |
---|
1291 | + COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_CHECK)) |
---|
1292 | + continue; |
---|
1293 | + |
---|
1294 | + /* |
---|
1295 | + * this file will hold the actual metadata |
---|
1296 | + * to be transferred |
---|
1297 | + */ |
---|
1298 | + md_tmp = strdup("/tmp/scp.md.XXXXXX"); |
---|
1299 | + md_tmp = mktemp(md_tmp); |
---|
1300 | + |
---|
1301 | + if(copyfile(name, md_tmp, 0, |
---|
1302 | + COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_PACK) == 0) |
---|
1303 | + { |
---|
1304 | + /* |
---|
1305 | + * this is the fake name to display |
---|
1306 | + */ |
---|
1307 | + snprintf(md_name, sizeof md_name, "%s/._%s", dirname(name), basename(name)); |
---|
1308 | + name = md_name; |
---|
1309 | + md_flag = 1; |
---|
1310 | + if (verbose_mode) |
---|
1311 | + fprintf(stderr, "copyfile(%s, %s, PACK)\n", name, md_tmp); |
---|
1312 | + goto md_next; |
---|
1313 | + } |
---|
1314 | + } else |
---|
1315 | + md_flag = 0; |
---|
1316 | +#endif |
---|
1317 | } |
---|
1318 | } |
---|
1319 | |
---|
1320 | @@ -891,6 +967,10 @@ |
---|
1321 | if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) |
---|
1322 | targisdir = 1; |
---|
1323 | for (first = 1;; first = 0) { |
---|
1324 | +#if HAVE_COPYFILE |
---|
1325 | + char md_src[MAXPATHLEN]; |
---|
1326 | + char md_dst[MAXPATHLEN]; |
---|
1327 | +#endif |
---|
1328 | cp = buf; |
---|
1329 | if (atomicio(read, remin, cp, 1) != 1) |
---|
1330 | return; |
---|
1331 | @@ -1024,10 +1104,51 @@ |
---|
1332 | } |
---|
1333 | omode = mode; |
---|
1334 | mode |= S_IWRITE; |
---|
1335 | + |
---|
1336 | +#if HAVE_COPYFILE |
---|
1337 | + if (copy_xattr && !strncmp(basename(curfile), "._", 2)) |
---|
1338 | + { |
---|
1339 | + int mdfd; |
---|
1340 | + if (targisdir) |
---|
1341 | + { |
---|
1342 | + snprintf(md_src, sizeof md_src, "%s.XXXXXX", np); |
---|
1343 | + snprintf(md_dst, sizeof md_dst, "%s/%s", |
---|
1344 | + dirname(np), basename(np) + 2); |
---|
1345 | + if((mdfd = mkstemp(md_src)) < 0) |
---|
1346 | + continue; |
---|
1347 | + } |
---|
1348 | + else |
---|
1349 | + { |
---|
1350 | + snprintf(md_src, sizeof md_src, "%s/._%s.XXXXXX", |
---|
1351 | + dirname(np), basename(np)); |
---|
1352 | + snprintf(md_dst, sizeof md_dst, "%s", np); |
---|
1353 | + if((mdfd = mkstemp(md_src)) < 0) |
---|
1354 | + continue; |
---|
1355 | + } |
---|
1356 | + if (mdfd >= 0) |
---|
1357 | + close(mdfd); |
---|
1358 | + np = md_src; |
---|
1359 | + } |
---|
1360 | +#endif |
---|
1361 | if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { |
---|
1362 | bad: run_err("%s: %s", np, strerror(errno)); |
---|
1363 | continue; |
---|
1364 | } |
---|
1365 | +#ifdef __APPLE_XSAN__ |
---|
1366 | + { |
---|
1367 | + /* |
---|
1368 | + * Pre-allocate blocks for the destination file. |
---|
1369 | + */ |
---|
1370 | + fstore_t fst; |
---|
1371 | + |
---|
1372 | + fst.fst_flags = 0; |
---|
1373 | + fst.fst_posmode = F_PEOFPOSMODE; |
---|
1374 | + fst.fst_offset = 0; |
---|
1375 | + fst.fst_length = size; |
---|
1376 | + |
---|
1377 | + (void) fcntl(ofd, F_PREALLOCATE, &fst); |
---|
1378 | + } |
---|
1379 | +#endif /* __APPLE_XSAN__ */ |
---|
1380 | (void) atomicio(vwrite, remout, "", 1); |
---|
1381 | if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) { |
---|
1382 | (void) close(ofd); |
---|
1383 | @@ -1111,6 +1232,29 @@ |
---|
1384 | wrerrno = errno; |
---|
1385 | } |
---|
1386 | (void) response(); |
---|
1387 | +#ifdef HAVE_COPYFILE |
---|
1388 | + if (copy_xattr && strncmp(basename(np), "._", 2) == 0) |
---|
1389 | + { |
---|
1390 | + if (verbose_mode) |
---|
1391 | + fprintf(stderr, "copyfile(%s, %s, UNPACK)\n", md_src, md_dst); |
---|
1392 | + if(!copyfile(md_src, md_dst, 0, |
---|
1393 | + COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_UNPACK) < 0) |
---|
1394 | + { |
---|
1395 | + snprintf(md_dst, sizeof md_dst, "%s/._%s", |
---|
1396 | + dirname(md_dst), basename(md_dst)); |
---|
1397 | + rename(md_src, md_dst); |
---|
1398 | + } else |
---|
1399 | + unlink(md_src); |
---|
1400 | + if (setimes && wrerr == NO) { |
---|
1401 | + setimes = 0; |
---|
1402 | + if (utimes(md_dst, tv) < 0) { |
---|
1403 | + run_err("%s: set times: %s", |
---|
1404 | + np, strerror(errno)); |
---|
1405 | + wrerr = DISPLAYED; |
---|
1406 | + } |
---|
1407 | + } |
---|
1408 | + } else |
---|
1409 | +#endif |
---|
1410 | if (setimes && wrerr == NO) { |
---|
1411 | setimes = 0; |
---|
1412 | if (utimes(np, tv) < 0) { |
---|
1413 | @@ -1172,7 +1316,11 @@ |
---|
1414 | usage(void) |
---|
1415 | { |
---|
1416 | (void) fprintf(stderr, |
---|
1417 | +#if HAVE_COPYFILE |
---|
1418 | + "usage: scp [-12346BCEpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" |
---|
1419 | +#else |
---|
1420 | "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" |
---|
1421 | +#endif |
---|
1422 | " [-l limit] [-o ssh_option] [-P port] [-S program]\n" |
---|
1423 | " [[user@]host1:]file1 ... [[user@]host2:]file2\n"); |
---|
1424 | exit(1); |
---|
1425 | --- a/servconf.c 2008-11-03 09:23:45.000000000 +0100 |
---|
1426 | +++ b/servconf.c 2009-02-26 01:14:06.000000000 +0100 |
---|
1427 | @@ -135,7 +138,7 @@ |
---|
1428 | { |
---|
1429 | /* Portable-specific options */ |
---|
1430 | if (options->use_pam == -1) |
---|
1431 | - options->use_pam = 0; |
---|
1432 | + options->use_pam = 1; |
---|
1433 | |
---|
1434 | /* Standard Options */ |
---|
1435 | if (options->protocol == SSH_PROTO_UNKNOWN) |
---|
1436 | @@ -213,8 +213,8 @@ |
---|
1437 | options->gss_strict_acceptor = 1; |
---|
1438 | if (options->gss_store_rekey == -1) |
---|
1439 | options->gss_store_rekey = 0; |
---|
1440 | if (options->password_authentication == -1) |
---|
1441 | - options->password_authentication = 1; |
---|
1442 | + options->password_authentication = 0; |
---|
1443 | if (options->kbd_interactive_authentication == -1) |
---|
1444 | options->kbd_interactive_authentication = 0; |
---|
1445 | if (options->challenge_response_authentication == -1) |
---|
1446 | @@ -542,7 +559,7 @@ |
---|
1447 | if ((pw = getpwnam(user)) == NULL) { |
---|
1448 | debug("Can't match group at line %d because user %.100s does " |
---|
1449 | "not exist", line, user); |
---|
1450 | - } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) { |
---|
1451 | + } else if (ga_init(pw) == 0) { |
---|
1452 | debug("Can't Match group because user %.100s not in any group " |
---|
1453 | "at line %d", user, line); |
---|
1454 | } else if (ga_match_pattern_list(grps) != 1) { |
---|
1455 | --- a/session.c 2009-01-28 06:29:49.000000000 +0100 |
---|
1456 | +++ b/session.c 2009-02-26 01:14:06.000000000 +0100 |
---|
1457 | @@ -2088,8 +2088,10 @@ |
---|
1458 | n_bytes = packet_remaining(); |
---|
1459 | tty_parse_modes(s->ttyfd, &n_bytes); |
---|
1460 | |
---|
1461 | +#ifndef __APPLE_PRIVPTY__ |
---|
1462 | if (!use_privsep) |
---|
1463 | pty_setowner(s->pw, s->tty); |
---|
1464 | +#endif |
---|
1465 | |
---|
1466 | /* Set window size from the packet. */ |
---|
1467 | pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); |
---|
1468 | @@ -2327,9 +2329,11 @@ |
---|
1469 | if (s->pid != 0) |
---|
1470 | record_logout(s->pid, s->tty, s->pw->pw_name); |
---|
1471 | |
---|
1472 | +#ifndef __APPLE_PRIVPTY__ |
---|
1473 | /* Release the pseudo-tty. */ |
---|
1474 | if (getuid() == 0) |
---|
1475 | pty_release(s->tty); |
---|
1476 | +#endif |
---|
1477 | |
---|
1478 | /* |
---|
1479 | * Close the server side of the socket pairs. We must do this after |
---|
1480 | --- a/ssh-add.0 2009-02-23 01:18:15.000000000 +0100 |
---|
1481 | +++ b/ssh-add.0 2009-02-26 01:14:06.000000000 +0100 |
---|
1482 | @@ -1,10 +1,10 @@ |
---|
1483 | SSH-ADD(1) OpenBSD Reference Manual SSH-ADD(1) |
---|
1484 | |
---|
1485 | NAME |
---|
1486 | - ssh-add - adds private key identities to the authentication agent |
---|
1487 | + ssh-add -- adds private key identities to the authentication agent |
---|
1488 | |
---|
1489 | SYNOPSIS |
---|
1490 | - ssh-add [-cDdLlXx] [-t life] [file ...] |
---|
1491 | + ssh-add [-cDdLlXxKk] [-t life] [file ...] |
---|
1492 | ssh-add -s pkcs11 |
---|
1493 | ssh-add -e pkcs11 |
---|
1494 | |
---|
1495 | @@ -58,6 +58,13 @@ |
---|
1496 | |
---|
1497 | -x Lock the agent with a password. |
---|
1498 | |
---|
1499 | + -K When adding identities, each passphrase will also be stored in |
---|
1500 | + your keychain. When removing identities with -d, each passphrase |
---|
1501 | + will be removed from your keychain. |
---|
1502 | + |
---|
1503 | + -k Add identities to the agent using any passphrases stored in your |
---|
1504 | + keychain. |
---|
1505 | + |
---|
1506 | ENVIRONMENT |
---|
1507 | DISPLAY and SSH_ASKPASS |
---|
1508 | If ssh-add needs a passphrase, it will read the passphrase from |
---|
1509 | --- a/ssh-add.1 2007-06-12 16:00:27.000000000 +0200 |
---|
1510 | +++ b/ssh-add.1 2008-04-18 00:15:22.000000000 +0200 |
---|
1511 | @@ -45,7 +45,7 @@ |
---|
1512 | .Nd adds RSA or DSA identities to the authentication agent |
---|
1513 | .Sh SYNOPSIS |
---|
1514 | .Nm ssh-add |
---|
1515 | -.Op Fl cDdLlXx |
---|
1516 | +.Op Fl cDdLlXxKk |
---|
1517 | .Op Fl t Ar life |
---|
1518 | .Op Ar |
---|
1519 | .Nm ssh-add |
---|
1520 | @@ -121,6 +121,12 @@ |
---|
1521 | Unlock the agent. |
---|
1522 | .It Fl x |
---|
1523 | Lock the agent with a password. |
---|
1524 | +.It Fl K |
---|
1525 | +When adding identities, each passphrase will also be stored in your |
---|
1526 | +keychain. When removing identities with -d, each passphrase will be |
---|
1527 | +removed from your keychain. |
---|
1528 | +.It Fl k |
---|
1529 | +Add identities to the agent using any passphrases stored in your keychain. |
---|
1530 | .El |
---|
1531 | .Sh ENVIRONMENT |
---|
1532 | .Bl -tag -width Ds |
---|
1533 | --- a/ssh-add.c 2008-02-28 09:13:52.000000000 +0100 |
---|
1534 | +++ b/ssh-add.c 2008-04-18 00:15:22.000000000 +0200 |
---|
1535 | @@ -62,6 +62,7 @@ |
---|
1536 | #include "authfile.h" |
---|
1537 | #include "pathnames.h" |
---|
1538 | #include "misc.h" |
---|
1539 | +#include "keychain.h" |
---|
1540 | |
---|
1541 | /* argv0 */ |
---|
1542 | extern char *__progname; |
---|
1543 | @@ -93,12 +94,24 @@ |
---|
1544 | } |
---|
1545 | |
---|
1546 | static int |
---|
1547 | -delete_file(AuthenticationConnection *ac, const char *filename) |
---|
1548 | +add_from_keychain(AuthenticationConnection *ac) |
---|
1549 | +{ |
---|
1550 | + if (ssh_add_from_keychain(ac) == 0) |
---|
1551 | + return -1; |
---|
1552 | + |
---|
1553 | + fprintf(stderr, "Added keychain identities.\n"); |
---|
1554 | + return 0; |
---|
1555 | +} |
---|
1556 | + |
---|
1557 | +static int |
---|
1558 | +delete_file(AuthenticationConnection *ac, int keychain, const char *filename) |
---|
1559 | { |
---|
1560 | Key *public; |
---|
1561 | char *comment = NULL; |
---|
1562 | int ret = -1; |
---|
1563 | |
---|
1564 | + if (keychain) |
---|
1565 | + remove_from_keychain(filename); |
---|
1566 | public = key_load_public(filename, &comment); |
---|
1567 | if (public == NULL) { |
---|
1568 | printf("Bad key file %s\n", filename); |
---|
1569 | @@ -136,7 +149,7 @@ |
---|
1570 | } |
---|
1571 | |
---|
1572 | static int |
---|
1573 | -add_file(AuthenticationConnection *ac, const char *filename) |
---|
1574 | +add_file(AuthenticationConnection *ac, int keychain, const char *filename) |
---|
1575 | { |
---|
1576 | Key *private; |
---|
1577 | char *comment = NULL; |
---|
1578 | @@ -159,11 +172,16 @@ |
---|
1579 | |
---|
1580 | /* At first, try empty passphrase */ |
---|
1581 | private = key_parse_private(&keyblob, filename, "", &comment); |
---|
1582 | + if (keychain && private != NULL) |
---|
1583 | + store_in_keychain(filename, ""); |
---|
1584 | if (comment == NULL) |
---|
1585 | comment = xstrdup(filename); |
---|
1586 | /* try last */ |
---|
1587 | - if (private == NULL && pass != NULL) |
---|
1588 | + if (private == NULL && pass != NULL) { |
---|
1589 | private = key_parse_private(&keyblob, filename, pass, NULL); |
---|
1590 | + if (keychain && private != NULL) |
---|
1591 | + store_in_keychain(filename, pass); |
---|
1592 | + } |
---|
1593 | if (private == NULL) { |
---|
1594 | /* clear passphrase since it did not work */ |
---|
1595 | clear_pass(); |
---|
1596 | @@ -177,9 +195,12 @@ |
---|
1597 | return -1; |
---|
1598 | } |
---|
1599 | private = key_parse_private(&keyblob, filename, pass, |
---|
1600 | &comment); |
---|
1601 | - if (private != NULL) |
---|
1602 | + if (private != NULL) { |
---|
1603 | + if (keychain) |
---|
1604 | + store_in_keychain(filename, pass); |
---|
1605 | break; |
---|
1606 | + } |
---|
1607 | clear_pass(); |
---|
1608 | snprintf(msg, sizeof msg, |
---|
1609 | "Bad passphrase, try again for %.200s: ", comment); |
---|
1610 | @@ -295,13 +316,13 @@ |
---|
1611 | } |
---|
1612 | |
---|
1613 | static int |
---|
1614 | -do_file(AuthenticationConnection *ac, int deleting, char *file) |
---|
1615 | +do_file(AuthenticationConnection *ac, int deleting, int keychain, char *file) |
---|
1616 | { |
---|
1617 | if (deleting) { |
---|
1618 | - if (delete_file(ac, file) == -1) |
---|
1619 | + if (delete_file(ac, keychain, file) == -1) |
---|
1620 | return -1; |
---|
1621 | } else { |
---|
1622 | - if (add_file(ac, file) == -1) |
---|
1623 | + if (add_file(ac, keychain, file) == -1) |
---|
1624 | return -1; |
---|
1625 | } |
---|
1626 | return 0; |
---|
1627 | @@ -324,5 +345,10 @@ |
---|
1628 | fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n"); |
---|
1629 | fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n"); |
---|
1630 | +#ifdef KEYCHAIN |
---|
1631 | + fprintf(stderr, " -k Add all identities stored in your keychain.\n"); |
---|
1632 | + fprintf(stderr, " -K Store passphrases in your keychain.\n"); |
---|
1633 | + fprintf(stderr, " With -d, remove passphrases from your keychain.\n"); |
---|
1634 | +#endif |
---|
1635 | } |
---|
1636 | |
---|
1637 | int |
---|
1638 | @@ -334,6 +360,7 @@ |
---|
1639 | AuthenticationConnection *ac = NULL; |
---|
1640 | char *sc_reader_id = NULL; |
---|
1641 | int i, ch, deleting = 0, ret = 0; |
---|
1642 | + int keychain = 0; |
---|
1643 | |
---|
1644 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
---|
1645 | sanitise_stdfd(); |
---|
1646 | @@ -351,7 +378,7 @@ |
---|
1647 | "Could not open a connection to your authentication agent.\n"); |
---|
1648 | exit(2); |
---|
1649 | } |
---|
1650 | - while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) { |
---|
1651 | + while ((ch = getopt(argc, argv, "lLcdDxXe:s:kKt:")) != -1) { |
---|
1652 | switch (ch) { |
---|
1653 | case 'l': |
---|
1654 | case 'L': |
---|
1655 | @@ -373,6 +400,13 @@ |
---|
1656 | if (delete_all(ac) == -1) |
---|
1657 | ret = 1; |
---|
1658 | goto done; |
---|
1659 | + case 'k': |
---|
1660 | + if (add_from_keychain(ac) == -1) |
---|
1661 | + ret = 1; |
---|
1662 | + goto done; |
---|
1663 | + case 'K': |
---|
1664 | + keychain = 1; |
---|
1665 | + break; |
---|
1666 | case 's': |
---|
1667 | sc_reader_id = optarg; |
---|
1668 | break; |
---|
1669 | @@ -403,6 +437,7 @@ |
---|
1670 | if (argc == 0) { |
---|
1671 | char buf[MAXPATHLEN]; |
---|
1672 | struct passwd *pw; |
---|
1673 | + char *pw_dir; |
---|
1674 | struct stat st; |
---|
1675 | int count = 0; |
---|
1676 | |
---|
1677 | @@ -413,21 +448,25 @@ |
---|
1678 | goto done; |
---|
1679 | } |
---|
1680 | |
---|
1681 | + pw_dir = xstrdup(pw->pw_dir); |
---|
1682 | + |
---|
1683 | for (i = 0; default_files[i]; i++) { |
---|
1684 | - snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, |
---|
1685 | + snprintf(buf, sizeof(buf), "%s/%s", pw_dir, |
---|
1686 | default_files[i]); |
---|
1687 | if (stat(buf, &st) < 0) |
---|
1688 | continue; |
---|
1689 | - if (do_file(ac, deleting, buf) == -1) |
---|
1690 | + if (do_file(ac, deleting, keychain, buf) == -1) |
---|
1691 | ret = 1; |
---|
1692 | else |
---|
1693 | count++; |
---|
1694 | } |
---|
1695 | if (count == 0) |
---|
1696 | ret = 1; |
---|
1697 | + |
---|
1698 | + xfree(pw_dir); |
---|
1699 | } else { |
---|
1700 | for (i = 0; i < argc; i++) { |
---|
1701 | - if (do_file(ac, deleting, argv[i]) == -1) |
---|
1702 | + if (do_file(ac, deleting, keychain, argv[i]) == -1) |
---|
1703 | ret = 1; |
---|
1704 | } |
---|
1705 | } |
---|
1706 | --- a/ssh-agent.c 2008-07-04 15:10:49.000000000 +0200 |
---|
1707 | +++ b/ssh-agent.c 2009-02-26 01:14:06.000000000 +0100 |
---|
1708 | @@ -65,6 +65,9 @@ |
---|
1709 | #include <time.h> |
---|
1710 | #include <string.h> |
---|
1711 | #include <unistd.h> |
---|
1712 | +#ifdef __APPLE_LAUNCHD__ |
---|
1713 | +#include <launch.h> |
---|
1714 | +#endif |
---|
1715 | |
---|
1716 | #include "xmalloc.h" |
---|
1717 | #include "ssh.h" |
---|
1718 | @@ -72,9 +75,11 @@ |
---|
1719 | #include "buffer.h" |
---|
1720 | #include "key.h" |
---|
1721 | #include "authfd.h" |
---|
1722 | +#include "authfile.h" |
---|
1723 | #include "compat.h" |
---|
1724 | #include "log.h" |
---|
1725 | #include "misc.h" |
---|
1726 | +#include "keychain.h" |
---|
1727 | |
---|
1728 | #ifdef SMARTCARD |
---|
1729 | #include "scard.h" |
---|
1730 | @@ -714,6 +719,61 @@ |
---|
1731 | } |
---|
1732 | #endif /* SMARTCARD */ |
---|
1733 | |
---|
1734 | +static int |
---|
1735 | +add_identity_callback(const char *filename, const char *passphrase) |
---|
1736 | +{ |
---|
1737 | + Key *k; |
---|
1738 | + int version; |
---|
1739 | + Idtab *tab; |
---|
1740 | + |
---|
1741 | + if ((k = key_load_private(filename, passphrase, NULL)) == NULL) |
---|
1742 | + return 1; |
---|
1743 | + switch (k->type) { |
---|
1744 | + case KEY_RSA: |
---|
1745 | + case KEY_RSA1: |
---|
1746 | + if (RSA_blinding_on(k->rsa, NULL) != 1) { |
---|
1747 | + key_free(k); |
---|
1748 | + return 1; |
---|
1749 | + } |
---|
1750 | + break; |
---|
1751 | + } |
---|
1752 | + version = k->type == KEY_RSA1 ? 1 : 2; |
---|
1753 | + tab = idtab_lookup(version); |
---|
1754 | + if (lookup_identity(k, version) == NULL) { |
---|
1755 | + Identity *id = xmalloc(sizeof(Identity)); |
---|
1756 | + id->key = k; |
---|
1757 | + id->comment = xstrdup(filename); |
---|
1758 | + if (id->comment == NULL) { |
---|
1759 | + key_free(k); |
---|
1760 | + return 1; |
---|
1761 | + } |
---|
1762 | + id->death = 0; |
---|
1763 | + id->confirm = 0; |
---|
1764 | + TAILQ_INSERT_TAIL(&tab->idlist, id, next); |
---|
1765 | + tab->nentries++; |
---|
1766 | + } else { |
---|
1767 | + key_free(k); |
---|
1768 | + return 1; |
---|
1769 | + } |
---|
1770 | + |
---|
1771 | + return 0; |
---|
1772 | +} |
---|
1773 | + |
---|
1774 | +static void |
---|
1775 | +process_add_from_keychain(SocketEntry *e) |
---|
1776 | +{ |
---|
1777 | + int result; |
---|
1778 | + |
---|
1779 | + result = add_identities_using_keychain(&add_identity_callback); |
---|
1780 | + |
---|
1781 | + /* e will be NULL when ssh-agent adds keys on its own at startup */ |
---|
1782 | + if (e) { |
---|
1783 | + buffer_put_int(&e->output, 1); |
---|
1784 | + buffer_put_char(&e->output, |
---|
1785 | + result ? SSH_AGENT_FAILURE : SSH_AGENT_SUCCESS); |
---|
1786 | + } |
---|
1787 | +} |
---|
1788 | + |
---|
1789 | /* dispatch incoming messages */ |
---|
1790 | |
---|
1791 | static void |
---|
1792 | @@ -806,6 +866,9 @@ |
---|
1793 | process_remove_smartcard_key(e); |
---|
1794 | break; |
---|
1795 | #endif /* ENABLE_PKCS11 */ |
---|
1796 | + case SSH_AGENTC_ADD_FROM_KEYCHAIN: |
---|
1797 | + process_add_from_keychain(e); |
---|
1798 | + break; |
---|
1799 | default: |
---|
1800 | /* Unknown message. Respond with failure. */ |
---|
1801 | error("Unknown message %d", type); |
---|
1802 | @@ -1046,7 +1109,11 @@ |
---|
1803 | int |
---|
1804 | main(int ac, char **av) |
---|
1805 | { |
---|
1806 | +#ifdef __APPLE_LAUNCHD__ |
---|
1807 | + int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, l_flag = 0; |
---|
1808 | +#else |
---|
1809 | int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; |
---|
1810 | +#endif |
---|
1811 | int sock, fd, ch, result, saved_errno; |
---|
1812 | u_int nalloc; |
---|
1813 | char *shell, *format, *pidstr, *agentsocket = NULL; |
---|
1814 | @@ -1080,7 +1147,11 @@ |
---|
1815 | init_rng(); |
---|
1816 | seed_rng(); |
---|
1817 | |
---|
1818 | +#ifdef __APPLE_LAUNCHD__ |
---|
1819 | + while ((ch = getopt(ac, av, "cdklsa:t:")) != -1) { |
---|
1820 | +#else |
---|
1821 | while ((ch = getopt(ac, av, "cdksa:t:")) != -1) { |
---|
1822 | +#endif |
---|
1823 | switch (ch) { |
---|
1824 | case 'c': |
---|
1825 | if (s_flag) |
---|
1826 | @@ -1090,6 +1161,11 @@ |
---|
1827 | case 'k': |
---|
1828 | k_flag++; |
---|
1829 | break; |
---|
1830 | +#ifdef __APPLE_LAUNCHD__ |
---|
1831 | + case 'l': |
---|
1832 | + l_flag++; |
---|
1833 | + break; |
---|
1834 | +#endif |
---|
1835 | case 's': |
---|
1836 | if (c_flag) |
---|
1837 | usage(); |
---|
1838 | @@ -1116,7 +1192,11 @@ |
---|
1839 | ac -= optind; |
---|
1840 | av += optind; |
---|
1841 | |
---|
1842 | +#ifdef __APPPLE_LAUNCHD__ |
---|
1843 | + if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || l_flag)) |
---|
1844 | +#else |
---|
1845 | if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) |
---|
1846 | +#endif |
---|
1847 | usage(); |
---|
1848 | |
---|
1849 | if (ac == 0 && !c_flag && !s_flag) { |
---|
1850 | @@ -1172,6 +1252,53 @@ |
---|
1851 | * Create socket early so it will exist before command gets run from |
---|
1852 | * the parent. |
---|
1853 | */ |
---|
1854 | +#ifdef __APPLE_LAUNCHD__ |
---|
1855 | + if (l_flag) { |
---|
1856 | + launch_data_t resp, msg, tmp; |
---|
1857 | + size_t listeners_i; |
---|
1858 | + |
---|
1859 | + msg = launch_data_new_string(LAUNCH_KEY_CHECKIN); |
---|
1860 | + |
---|
1861 | + resp = launch_msg(msg); |
---|
1862 | + |
---|
1863 | + if (NULL == resp) { |
---|
1864 | + perror("launch_msg"); |
---|
1865 | + exit(1); |
---|
1866 | + } |
---|
1867 | + launch_data_free(msg); |
---|
1868 | + switch (launch_data_get_type(resp)) { |
---|
1869 | + case LAUNCH_DATA_ERRNO: |
---|
1870 | + errno = launch_data_get_errno(resp); |
---|
1871 | + perror("launch_msg response"); |
---|
1872 | + exit(1); |
---|
1873 | + case LAUNCH_DATA_DICTIONARY: |
---|
1874 | + break; |
---|
1875 | + default: |
---|
1876 | + fprintf(stderr, "launch_msg unknown response"); |
---|
1877 | + exit(1); |
---|
1878 | + } |
---|
1879 | + tmp = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS); |
---|
1880 | + |
---|
1881 | + if (NULL == tmp) { |
---|
1882 | + fprintf(stderr, "no sockets\n"); |
---|
1883 | + exit(1); |
---|
1884 | + } |
---|
1885 | + |
---|
1886 | + tmp = launch_data_dict_lookup(tmp, "Listeners"); |
---|
1887 | + |
---|
1888 | + if (NULL == tmp) { |
---|
1889 | + fprintf(stderr, "no known listeners\n"); |
---|
1890 | + exit(1); |
---|
1891 | + } |
---|
1892 | + |
---|
1893 | + for (listeners_i = 0; listeners_i < launch_data_array_get_count(tmp); listeners_i++) { |
---|
1894 | + launch_data_t obj_at_ind = launch_data_array_get_index(tmp, listeners_i); |
---|
1895 | + new_socket(AUTH_SOCKET, launch_data_get_fd(obj_at_ind)); |
---|
1896 | + } |
---|
1897 | + |
---|
1898 | + launch_data_free(resp); |
---|
1899 | + } else { |
---|
1900 | +#endif |
---|
1901 | sock = socket(AF_UNIX, SOCK_STREAM, 0); |
---|
1902 | if (sock < 0) { |
---|
1903 | perror("socket"); |
---|
1904 | @@ -1193,6 +1320,14 @@ |
---|
1905 | perror("listen"); |
---|
1906 | cleanup_exit(1); |
---|
1907 | } |
---|
1908 | +#ifdef __APPLE_LAUNCHD__ |
---|
1909 | + } |
---|
1910 | +#endif |
---|
1911 | + |
---|
1912 | +#ifdef __APPLE_LAUNCHD__ |
---|
1913 | + if (l_flag) |
---|
1914 | + goto skip2; |
---|
1915 | +#endif |
---|
1916 | |
---|
1917 | /* |
---|
1918 | * Fork, and have the parent execute the command, if any, or present |
---|
1919 | @@ -1261,6 +1396,7 @@ |
---|
1920 | |
---|
1921 | skip: |
---|
1922 | new_socket(AUTH_SOCKET, sock); |
---|
1923 | +skip2: |
---|
1924 | if (ac > 0) |
---|
1925 | parent_alive_interval = 10; |
---|
1926 | idtab_init(); |
---|
1927 | @@ -1271,6 +1407,10 @@ |
---|
1928 | signal(SIGTERM, cleanup_handler); |
---|
1929 | nalloc = 0; |
---|
1930 | |
---|
1931 | +#ifdef KEYCHAIN |
---|
1932 | + process_add_from_keychain(NULL); |
---|
1933 | +#endif |
---|
1934 | + |
---|
1935 | while (1) { |
---|
1936 | prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp); |
---|
1937 | result = select(max_fd + 1, readsetp, writesetp, NULL, tvp); |
---|
1938 | --- a/ssh-keysign.8 2007-06-05 10:27:13.000000000 +0200 |
---|
1939 | +++ b/ssh-keysign.8 2008-07-28 19:29:42.000000000 +0200 |
---|
1940 | @@ -71,6 +71,9 @@ |
---|
1941 | Since they are readable only by root, |
---|
1942 | .Nm |
---|
1943 | must be set-uid root if host-based authentication is used. |
---|
1944 | +Note that |
---|
1945 | +.Nm |
---|
1946 | +is not set-uid by default on Mac OS X. |
---|
1947 | .Pp |
---|
1948 | .It Pa /etc/ssh/ssh_host_dsa_key-cert.pub |
---|
1949 | .It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub |
---|
1950 | --- a/sshconnect1.c 2006-11-07 13:14:42.000000000 +0100 |
---|
1951 | +++ b/sshconnect1.c 2008-10-09 01:55:13.000000000 +0200 |
---|
1952 | @@ -47,6 +47,7 @@ |
---|
1953 | #include "canohost.h" |
---|
1954 | #include "hostfile.h" |
---|
1955 | #include "auth.h" |
---|
1956 | +#include "keychain.h" |
---|
1957 | |
---|
1958 | /* Session id for the current session. */ |
---|
1959 | u_char session_id[16]; |
---|
1960 | @@ -260,6 +261,10 @@ |
---|
1961 | snprintf(buf, sizeof(buf), |
---|
1962 | "Enter passphrase for RSA key '%.100s': ", comment); |
---|
1963 | for (i = 0; i < options.number_of_password_prompts; i++) { |
---|
1964 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1965 | + passphrase = keychain_read_passphrase(comment, options.ask_pass_gui); |
---|
1966 | + if (passphrase == NULL) |
---|
1967 | +#endif |
---|
1968 | passphrase = read_passphrase(buf, 0); |
---|
1969 | if (strcmp(passphrase, "") != 0) { |
---|
1970 | private = key_load_private_type(KEY_RSA1, |
---|
1971 | --- a/sshconnect2.c 2008-11-05 06:20:47.000000000 +0100 |
---|
1972 | +++ b/sshconnect2.c 2009-02-26 01:14:06.000000000 +0100 |
---|
1973 | @@ -69,6 +69,7 @@ |
---|
1974 | #include "pathnames.h" |
---|
1975 | #include "uidswap.h" |
---|
1976 | #include "jpake.h" |
---|
1977 | +#include "keychain.h" |
---|
1978 | |
---|
1979 | #ifdef GSSAPI |
---|
1980 | #include "ssh-gss.h" |
---|
1981 | @@ -1447,6 +1448,10 @@ |
---|
1982 | snprintf(prompt, sizeof prompt, |
---|
1983 | "Enter passphrase for key '%.100s': ", filename); |
---|
1984 | for (i = 0; i < options.number_of_password_prompts; i++) { |
---|
1985 | +#ifdef __APPLE_KEYCHAIN__ |
---|
1986 | + passphrase = keychain_read_passphrase(filename, options.ask_pass_gui); |
---|
1987 | + if (passphrase == NULL) |
---|
1988 | +#endif |
---|
1989 | passphrase = read_passphrase(prompt, 0); |
---|
1990 | if (strcmp(passphrase, "") != 0) { |
---|
1991 | private = key_load_private_type(KEY_UNSPEC, |
---|
1992 | --- a/sshd.0 2009-02-23 01:18:15.000000000 +0100 |
---|
1993 | +++ b/sshd.0 2009-02-26 01:14:06.000000000 +0100 |
---|
1994 | @@ -556,8 +556,8 @@ |
---|
1995 | |
---|
1996 | SEE ALSO |
---|
1997 | scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), |
---|
1998 | - ssh-keyscan(1), chroot(2), hosts_access(5), login.conf(5), moduli(5), |
---|
1999 | - sshd_config(5), inetd(8), sftp-server(8) |
---|
2000 | + ssh-keyscan(1), chroot(2), hosts_access(5), sshd_config(5) |
---|
2001 | + sftp-server(8) |
---|
2002 | |
---|
2003 | AUTHORS |
---|
2004 | OpenSSH is a derivative of the original and free ssh 1.2.12 release by |
---|
2005 | --- a/sshd.8 2008-11-03 09:21:21.000000000 +0100 |
---|
2006 | +++ b/sshd.8 2009-02-26 01:14:06.000000000 +0100 |
---|
2007 | @@ -873,10 +873,7 @@ |
---|
2008 | .Xr ssh-keyscan 1 , |
---|
2009 | .Xr chroot 2 , |
---|
2010 | .Xr hosts_access 5 , |
---|
2011 | -.Xr login.conf 5 , |
---|
2012 | -.Xr moduli 5 , |
---|
2013 | .Xr sshd_config 5 , |
---|
2014 | -.Xr inetd 8 , |
---|
2015 | .Xr sftp-server 8 |
---|
2016 | .Sh AUTHORS |
---|
2017 | OpenSSH is a derivative of the original and free |
---|
2018 | --- a/sshd.c 2009-01-28 06:31:23.000000000 +0100 |
---|
2019 | +++ b/sshd.c 2009-02-26 01:14:06.000000000 +0100 |
---|
2020 | @@ -1887,6 +1976,12 @@ |
---|
2021 | audit_event(SSH_AUTH_SUCCESS); |
---|
2022 | #endif |
---|
2023 | |
---|
2024 | +#ifdef USE_PAM |
---|
2025 | + if (options.use_pam) { |
---|
2026 | + do_pam_setcred(1); |
---|
2027 | + do_pam_session(); |
---|
2028 | + } |
---|
2029 | +#endif |
---|
2030 | #ifdef GSSAPI |
---|
2031 | if (options.gss_authentication) { |
---|
2032 | temporarily_use_uid(authctxt->pw); |
---|
2033 | @@ -1894,12 +1989,6 @@ |
---|
2034 | restore_uid(); |
---|
2035 | } |
---|
2036 | #endif |
---|
2037 | -#ifdef USE_PAM |
---|
2038 | - if (options.use_pam) { |
---|
2039 | - do_pam_setcred(1); |
---|
2040 | - do_pam_session(); |
---|
2041 | - } |
---|
2042 | -#endif |
---|
2043 | |
---|
2044 | /* |
---|
2045 | * In privilege separation, we fork another child and prepare |
---|
2046 | --- a/sshd_config 2008-07-02 14:35:43.000000000 +0200 |
---|
2047 | +++ b/sshd_config 2008-12-10 00:05:59.000000000 +0100 |
---|
2048 | @@ -32,7 +32,7 @@ |
---|
2049 | |
---|
2050 | # Logging |
---|
2051 | # obsoletes QuietMode and FascistLogging |
---|
2052 | -#SyslogFacility AUTH |
---|
2053 | +SyslogFacility AUTHPRIV |
---|
2054 | #LogLevel INFO |
---|
2055 | |
---|
2056 | # Authentication: |
---|
2057 | @@ -57,10 +57,11 @@ |
---|
2058 | # Don't read the user's ~/.rhosts and ~/.shosts files |
---|
2059 | #IgnoreRhosts yes |
---|
2060 | |
---|
2061 | -# To disable tunneled clear text passwords, change to no here! |
---|
2062 | -#PasswordAuthentication yes |
---|
2063 | +# To disable tunneled clear text passwords, change to no here! Also, |
---|
2064 | +# remember to set the UsePAM setting to 'no'. |
---|
2065 | +#PasswordAuthentication no |
---|
2066 | #PermitEmptyPasswords no |
---|
2067 | |
---|
2068 | # Change to no to disable s/key passwords |
---|
2069 | #ChallengeResponseAuthentication yes |
---|
2070 | |
---|
2071 | @@ -83,7 +90,10 @@ |
---|
2072 | # If you just want the PAM account and session checks to run without |
---|
2073 | # PAM authentication, then enable this but set PasswordAuthentication |
---|
2074 | # and ChallengeResponseAuthentication to 'no'. |
---|
2075 | -#UsePAM no |
---|
2076 | +# Also, PAM will deny null passwords by default. If you need to allow |
---|
2077 | +# null passwords, add the " nullok" option to the end of the |
---|
2078 | +# securityserver.so line in /etc/pam.d/sshd. |
---|
2079 | +#UsePAM yes |
---|
2080 | |
---|
2081 | #AllowAgentForwarding yes |
---|
2082 | #AllowTcpForwarding yes |
---|
2083 | --- a/sshd_config.0 2009-02-23 01:18:15.000000000 +0100 |
---|
2084 | +++ b/sshd_config.0 2009-02-26 01:14:06.000000000 +0100 |
---|
2085 | @@ -371,7 +365,7 @@ |
---|
2086 | |
---|
2087 | PasswordAuthentication |
---|
2088 | Specifies whether password authentication is allowed. The |
---|
2089 | - default is ``yes''. |
---|
2090 | + default is ``no''. |
---|
2091 | |
---|
2092 | PermitEmptyPasswords |
---|
2093 | When password authentication is allowed, it specifies whether the |
---|
2094 | @@ -535,7 +534,7 @@ |
---|
2095 | either PasswordAuthentication or ChallengeResponseAuthentication. |
---|
2096 | |
---|
2097 | If UsePAM is enabled, you will not be able to run sshd(8) as a |
---|
2098 | - non-root user. The default is ``no''. |
---|
2099 | + non-root user. The default is ``yes''. |
---|
2100 | |
---|
2101 | UsePrivilegeSeparation |
---|
2102 | Specifies whether sshd(8) separates privileges by creating an un- |
---|
2103 | --- a/sshd_config.5 2009-02-23 01:00:24.000000000 +0100 |
---|
2104 | +++ b/sshd_config.5 2009-02-26 01:14:06.000000000 +0100 |
---|
2105 | @@ -651,7 +666,7 @@ |
---|
2106 | .It Cm PasswordAuthentication |
---|
2107 | Specifies whether password authentication is allowed. |
---|
2108 | The default is |
---|
2109 | -.Dq yes . |
---|
2110 | +.Dq no . |
---|
2111 | .It Cm PermitEmptyPasswords |
---|
2112 | When password authentication is allowed, it specifies whether the |
---|
2113 | server allows login to accounts with empty password strings. |
---|
2114 | @@ -922,7 +942,7 @@ |
---|
2115 | .Xr sshd 8 |
---|
2116 | as a non-root user. |
---|
2117 | The default is |
---|
2118 | -.Dq no . |
---|
2119 | +.Dq yes . |
---|
2120 | .It Cm UsePrivilegeSeparation |
---|
2121 | Specifies whether |
---|
2122 | .Xr sshd 8 |
---|