| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: pam_ssh.c,v 1.17 2011/05/06 17:22:09 drochner Exp $ */ | | 1 | /* $NetBSD: pam_ssh.c,v 1.18 2011/12/16 17:30:12 drochner Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2003 Networks Associates Technology, Inc. | | 4 | * Copyright (c) 2003 Networks Associates Technology, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This software was developed for the FreeBSD Project by ThinkSec AS and | | 7 | * This software was developed for the FreeBSD Project by ThinkSec AS and |
8 | * NAI Labs, the Security Research Division of Network Associates, Inc. | | 8 | * NAI Labs, the Security Research Division of Network Associates, Inc. |
9 | * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the | | 9 | * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the |
10 | * DARPA CHATS research program. | | 10 | * DARPA CHATS research program. |
11 | * | | 11 | * |
12 | * Redistribution and use in source and binary forms, with or without | | 12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | | 13 | * modification, are permitted provided that the following conditions |
14 | * are met: | | 14 | * are met: |
| @@ -28,27 +28,27 @@ | | | @@ -28,27 +28,27 @@ |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
34 | * SUCH DAMAGE. | | 34 | * SUCH DAMAGE. |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | #ifdef __FreeBSD__ | | 38 | #ifdef __FreeBSD__ |
39 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_ssh/pam_ssh.c,v 1.40 2004/02/10 10:13:21 des Exp $"); | | 39 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_ssh/pam_ssh.c,v 1.40 2004/02/10 10:13:21 des Exp $"); |
40 | #else | | 40 | #else |
41 | __RCSID("$NetBSD: pam_ssh.c,v 1.17 2011/05/06 17:22:09 drochner Exp $"); | | 41 | __RCSID("$NetBSD: pam_ssh.c,v 1.18 2011/12/16 17:30:12 drochner Exp $"); |
42 | #endif | | 42 | #endif |
43 | | | 43 | |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/wait.h> | | 45 | #include <sys/wait.h> |
46 | | | 46 | |
47 | #include <errno.h> | | 47 | #include <errno.h> |
48 | #include <fcntl.h> | | 48 | #include <fcntl.h> |
49 | #include <paths.h> | | 49 | #include <paths.h> |
50 | #include <pwd.h> | | 50 | #include <pwd.h> |
51 | #include <signal.h> | | 51 | #include <signal.h> |
52 | #include <stdio.h> | | 52 | #include <stdio.h> |
53 | #include <string.h> | | 53 | #include <string.h> |
54 | #include <unistd.h> | | 54 | #include <unistd.h> |
| @@ -57,62 +57,64 @@ __RCSID("$NetBSD: pam_ssh.c,v 1.17 2011/ | | | @@ -57,62 +57,64 @@ __RCSID("$NetBSD: pam_ssh.c,v 1.17 2011/ |
57 | #define PAM_SM_SESSION | | 57 | #define PAM_SM_SESSION |
58 | | | 58 | |
59 | #include <security/pam_appl.h> | | 59 | #include <security/pam_appl.h> |
60 | #include <security/pam_modules.h> | | 60 | #include <security/pam_modules.h> |
61 | #include <security/openpam.h> | | 61 | #include <security/openpam.h> |
62 | | | 62 | |
63 | #include <openssl/evp.h> | | 63 | #include <openssl/evp.h> |
64 | | | 64 | |
65 | #include "key.h" | | 65 | #include "key.h" |
66 | #include "buffer.h" | | 66 | #include "buffer.h" |
67 | #include "authfd.h" | | 67 | #include "authfd.h" |
68 | #include "authfile.h" | | 68 | #include "authfile.h" |
69 | | | 69 | |
| | | 70 | #define ssh_add_identity(auth, key, comment) \ |
| | | 71 | ssh_add_identity_constrained(auth, key, comment, 0, 0) |
| | | 72 | |
70 | extern char **environ; | | 73 | extern char **environ; |
71 | | | 74 | |
72 | struct pam_ssh_key { | | 75 | struct pam_ssh_key { |
73 | Key *key; | | 76 | Key *key; |
74 | char *comment; | | 77 | char *comment; |
75 | }; | | 78 | }; |
76 | | | 79 | |
77 | static const char *pam_ssh_prompt = "SSH passphrase: "; | | 80 | static const char *pam_ssh_prompt = "SSH passphrase: "; |
78 | static const char *pam_ssh_have_keys = "pam_ssh_have_keys"; | | 81 | static const char *pam_ssh_have_keys = "pam_ssh_have_keys"; |
79 | | | 82 | |
80 | static const char *pam_ssh_keyfiles[] = { | | 83 | static const char *pam_ssh_keyfiles[] = { |
81 | ".ssh/identity", /* SSH1 RSA key */ | | 84 | ".ssh/identity", /* SSH1 RSA key */ |
82 | ".ssh/id_rsa", /* SSH2 RSA key */ | | 85 | ".ssh/id_rsa", /* SSH2 RSA key */ |
83 | ".ssh/id_dsa", /* SSH2 DSA key */ | | 86 | ".ssh/id_dsa", /* SSH2 DSA key */ |
84 | NULL | | 87 | NULL |
85 | }; | | 88 | }; |
86 | | | 89 | |
87 | static const char *pam_ssh_agent = "/usr/bin/ssh-agent"; | | 90 | static const char *pam_ssh_agent = "/usr/bin/ssh-agent"; |
88 | static const char *pam_ssh_agent_argv[] = { "ssh_agent", "-s", NULL }; | | 91 | static const char *const pam_ssh_agent_argv[] = { "ssh_agent", "-s", NULL }; |
89 | static const char *pam_ssh_agent_envp[] = { NULL }; | | 92 | static const char *const pam_ssh_agent_envp[] = { NULL }; |
90 | | | 93 | |
91 | /* | | 94 | /* |
92 | * Attempts to load a private key from the specified file in the specified | | 95 | * Attempts to load a private key from the specified file in the specified |
93 | * directory, using the specified passphrase. If successful, returns a | | 96 | * directory, using the specified passphrase. If successful, returns a |
94 | * struct pam_ssh_key containing the key and its comment. | | 97 | * struct pam_ssh_key containing the key and its comment. |
95 | */ | | 98 | */ |
96 | static struct pam_ssh_key * | | 99 | static struct pam_ssh_key * |
97 | pam_ssh_load_key(struct passwd *pwd, const char *kfn, const char *passphrase) | | 100 | pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase) |
98 | { | | 101 | { |
99 | struct pam_ssh_key *psk; | | 102 | struct pam_ssh_key *psk; |
100 | char fn[PATH_MAX]; | | 103 | char fn[PATH_MAX]; |
101 | char *comment; | | 104 | char *comment; |
102 | Key *key; | | 105 | Key *key; |
103 | | | 106 | |
104 | if (snprintf(fn, sizeof(fn), "%s/%s", pwd->pw_dir, kfn) > | | 107 | if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn)) |
105 | (int)sizeof(fn)) | | | |
106 | return (NULL); | | 108 | return (NULL); |
107 | comment = NULL; | | 109 | comment = NULL; |
108 | key = key_load_private(fn, passphrase, &comment); | | 110 | key = key_load_private(fn, passphrase, &comment); |
109 | if (key == NULL) { | | 111 | if (key == NULL) { |
110 | openpam_log(PAM_LOG_DEBUG, "failed to load key from %s", fn); | | 112 | openpam_log(PAM_LOG_DEBUG, "failed to load key from %s", fn); |
111 | if (comment != NULL) | | 113 | if (comment != NULL) |
112 | free(comment); | | 114 | free(comment); |
113 | return (NULL); | | 115 | return (NULL); |
114 | } | | 116 | } |
115 | | | 117 | |
116 | openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s", comment, fn); | | 118 | openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s", comment, fn); |
117 | if ((psk = malloc(sizeof(*psk))) == NULL) { | | 119 | if ((psk = malloc(sizeof(*psk))) == NULL) { |
118 | key_free(key); | | 120 | key_free(key); |
| @@ -134,78 +136,65 @@ pam_ssh_free_key(pam_handle_t *pamh __un | | | @@ -134,78 +136,65 @@ pam_ssh_free_key(pam_handle_t *pamh __un |
134 | struct pam_ssh_key *psk; | | 136 | struct pam_ssh_key *psk; |
135 | | | 137 | |
136 | psk = data; | | 138 | psk = data; |
137 | key_free(psk->key); | | 139 | key_free(psk->key); |
138 | free(psk->comment); | | 140 | free(psk->comment); |
139 | free(psk); | | 141 | free(psk); |
140 | } | | 142 | } |
141 | | | 143 | |
142 | PAM_EXTERN int | | 144 | PAM_EXTERN int |
143 | pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, | | 145 | pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, |
144 | int argc __unused, const char *argv[] __unused) | | 146 | int argc __unused, const char *argv[] __unused) |
145 | { | | 147 | { |
146 | const char **kfn, *passphrase, *user; | | 148 | const char **kfn, *passphrase, *user; |
| | | 149 | const void *item; |
147 | struct passwd *pwd, pwres; | | 150 | struct passwd *pwd, pwres; |
148 | struct pam_ssh_key *psk; | | 151 | struct pam_ssh_key *psk; |
149 | int nkeys, pam_err, pass; | | 152 | int nkeys, pam_err, pass; |
150 | char pwbuf[1024]; | | 153 | char pwbuf[1024]; |
151 | | | 154 | |
152 | /* PEM is not loaded by default */ | | 155 | /* PEM is not loaded by default */ |
153 | OpenSSL_add_all_algorithms(); | | 156 | OpenSSL_add_all_algorithms(); |
154 | | | 157 | |
155 | /* get user name and home directory */ | | 158 | /* get user name and home directory */ |
156 | pam_err = pam_get_user(pamh, &user, NULL); | | 159 | pam_err = pam_get_user(pamh, &user, NULL); |
157 | if (pam_err != PAM_SUCCESS) | | 160 | if (pam_err != PAM_SUCCESS) |
158 | return (pam_err); | | 161 | return (pam_err); |
159 | if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || | | 162 | if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || |
160 | pwd == NULL) | | 163 | pwd == NULL) |
161 | return (PAM_USER_UNKNOWN); | | 164 | return (PAM_USER_UNKNOWN); |
162 | if (pwd->pw_dir == NULL) | | 165 | if (pwd->pw_dir == NULL) |
163 | return (PAM_AUTH_ERR); | | 166 | return (PAM_AUTH_ERR); |
164 | | | 167 | |
165 | /* switch to user credentials */ | | 168 | /* switch to user credentials */ |
166 | pam_err = openpam_borrow_cred(pamh, pwd); | | 169 | pam_err = openpam_borrow_cred(pamh, pwd); |
167 | if (pam_err != PAM_SUCCESS) | | 170 | if (pam_err != PAM_SUCCESS) |
168 | return (pam_err); | | 171 | return (pam_err); |
169 | | | 172 | |
170 | #ifdef notyet | | 173 | pass = (pam_get_item(pamh, PAM_AUTHTOK, &item) == PAM_SUCCESS && |
171 | for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { | | 174 | item != NULL); |
172 | char path[MAXPATHLEN]; | | | |
173 | (void)snprintf(path, sizeof(path), "%s/%s", pwd->pw_dir, *kfn); | | | |
174 | if (access(path, R_OK) == 0) | | | |
175 | break; | | | |
176 | } | | | |
177 | | | | |
178 | if (*kfn == NULL) { | | | |
179 | openpam_restore_cred(pamh); | | | |
180 | return (PAM_AUTH_ERR); | | | |
181 | } | | | |
182 | #endif | | | |
183 | | | | |
184 | pass = (pam_get_item(pamh, PAM_AUTHTOK, | | | |
185 | (const void **)__UNCONST(&passphrase)) == PAM_SUCCESS); | | | |
186 | load_keys: | | 175 | load_keys: |
187 | /* get passphrase */ | | 176 | /* get passphrase */ |
188 | pam_err = pam_get_authtok(pamh, PAM_AUTHTOK, | | 177 | pam_err = pam_get_authtok(pamh, PAM_AUTHTOK, |
189 | &passphrase, pam_ssh_prompt); | | 178 | &passphrase, pam_ssh_prompt); |
190 | if (pam_err != PAM_SUCCESS) { | | 179 | if (pam_err != PAM_SUCCESS) { |
191 | openpam_restore_cred(pamh); | | 180 | openpam_restore_cred(pamh); |
192 | return (pam_err); | | 181 | return (pam_err); |
193 | } | | 182 | } |
194 | | | 183 | |
195 | /* try to load keys from all keyfiles we know of */ | | 184 | /* try to load keys from all keyfiles we know of */ |
196 | nkeys = 0; | | 185 | nkeys = 0; |
197 | for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { | | 186 | for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { |
198 | psk = pam_ssh_load_key(pwd, *kfn, passphrase); | | 187 | psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase); |
199 | if (psk != NULL) { | | 188 | if (psk != NULL) { |
200 | pam_set_data(pamh, *kfn, psk, pam_ssh_free_key); | | 189 | pam_set_data(pamh, *kfn, psk, pam_ssh_free_key); |
201 | ++nkeys; | | 190 | ++nkeys; |
202 | } | | 191 | } |
203 | } | | 192 | } |
204 | | | 193 | |
205 | /* | | 194 | /* |
206 | * If we tried an old token and didn't get anything, and | | 195 | * If we tried an old token and didn't get anything, and |
207 | * try_first_pass was specified, try again after prompting the | | 196 | * try_first_pass was specified, try again after prompting the |
208 | * user for a new passphrase. | | 197 | * user for a new passphrase. |
209 | */ | | 198 | */ |
210 | if (nkeys == 0 && pass == 1 && | | 199 | if (nkeys == 0 && pass == 1 && |
211 | openpam_get_option(pamh, "try_first_pass") != NULL) { | | 200 | openpam_get_option(pamh, "try_first_pass") != NULL) { |
| @@ -366,27 +355,27 @@ pam_ssh_add_keys_to_agent(pam_handle_t * | | | @@ -366,27 +355,27 @@ pam_ssh_add_keys_to_agent(pam_handle_t * |
366 | openpam_log(PAM_LOG_DEBUG, | | 355 | openpam_log(PAM_LOG_DEBUG, |
367 | "%s: cannot get authentication connection", | | 356 | "%s: cannot get authentication connection", |
368 | __func__); | | 357 | __func__); |
369 | pam_err = PAM_SYSTEM_ERR; | | 358 | pam_err = PAM_SYSTEM_ERR; |
370 | goto end; | | 359 | goto end; |
371 | } | | 360 | } |
372 | | | 361 | |
373 | /* look for keys to add to it */ | | 362 | /* look for keys to add to it */ |
374 | for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { | | 363 | for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { |
375 | const void *vp; | | 364 | const void *vp; |
376 | pam_err = pam_get_data(pamh, *kfn, &vp); | | 365 | pam_err = pam_get_data(pamh, *kfn, &vp); |
377 | psk = vp; | | 366 | psk = vp; |
378 | if (pam_err == PAM_SUCCESS && psk != NULL) { | | 367 | if (pam_err == PAM_SUCCESS && psk != NULL) { |
379 | if (ssh_add_identity_constrained(ac, psk->key, psk->comment, 0, 0)) | | 368 | if (ssh_add_identity(ac, psk->key, psk->comment)) |
380 | openpam_log(PAM_LOG_DEBUG, | | 369 | openpam_log(PAM_LOG_DEBUG, |
381 | "added %s to ssh agent", psk->comment); | | 370 | "added %s to ssh agent", psk->comment); |
382 | else | | 371 | else |
383 | openpam_log(PAM_LOG_DEBUG, "failed " | | 372 | openpam_log(PAM_LOG_DEBUG, "failed " |
384 | "to add %s to ssh agent", psk->comment); | | 373 | "to add %s to ssh agent", psk->comment); |
385 | /* we won't need the key again, so wipe it */ | | 374 | /* we won't need the key again, so wipe it */ |
386 | pam_set_data(pamh, *kfn, NULL, NULL); | | 375 | pam_set_data(pamh, *kfn, NULL, NULL); |
387 | } | | 376 | } |
388 | } | | 377 | } |
389 | pam_err = PAM_SUCCESS; | | 378 | pam_err = PAM_SUCCESS; |
390 | end: | | 379 | end: |
391 | /* disconnect from agent */ | | 380 | /* disconnect from agent */ |
392 | if (ac != NULL) | | 381 | if (ac != NULL) |