Fri Dec 16 17:30:12 2011 UTC ()
-remove remainders of the misguided changes in revs 1.5-1.9
-iron out more unnecessary differences to FreeBSD


(drochner)
diff -r1.17 -r1.18 src/lib/libpam/modules/pam_ssh/pam_ssh.c

cvs diff -r1.17 -r1.18 src/lib/libpam/modules/pam_ssh/pam_ssh.c (switch to unified diff)

--- src/lib/libpam/modules/pam_ssh/pam_ssh.c 2011/05/06 17:22:09 1.17
+++ src/lib/libpam/modules/pam_ssh/pam_ssh.c 2011/12/16 17:30:12 1.18
@@ -1,473 +1,462 @@ @@ -1,473 +1,462 @@
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:
15 * 1. Redistributions of source code must retain the above copyright 15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer. 16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright 17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the 18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution. 19 * documentation and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote 20 * 3. The name of the author may not be used to endorse or promote
21 * products derived from this software without specific prior written 21 * products derived from this software without specific prior written
22 * permission. 22 * permission.
23 * 23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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>
55 55
56#define PAM_SM_AUTH 56#define PAM_SM_AUTH
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
70extern char **environ; 73extern char **environ;
71 74
72struct pam_ssh_key { 75struct pam_ssh_key {
73 Key *key; 76 Key *key;
74 char *comment; 77 char *comment;
75}; 78};
76 79
77static const char *pam_ssh_prompt = "SSH passphrase: "; 80static const char *pam_ssh_prompt = "SSH passphrase: ";
78static const char *pam_ssh_have_keys = "pam_ssh_have_keys"; 81static const char *pam_ssh_have_keys = "pam_ssh_have_keys";
79 82
80static const char *pam_ssh_keyfiles[] = { 83static 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
87static const char *pam_ssh_agent = "/usr/bin/ssh-agent"; 90static const char *pam_ssh_agent = "/usr/bin/ssh-agent";
88static const char *pam_ssh_agent_argv[] = { "ssh_agent", "-s", NULL }; 91static const char *const pam_ssh_agent_argv[] = { "ssh_agent", "-s", NULL };
89static const char *pam_ssh_agent_envp[] = { NULL }; 92static 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 */
96static struct pam_ssh_key * 99static struct pam_ssh_key *
97pam_ssh_load_key(struct passwd *pwd, const char *kfn, const char *passphrase) 100pam_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);
119 free(comment); 121 free(comment);
120 return (NULL); 122 return (NULL);
121 } 123 }
122 psk->key = key; 124 psk->key = key;
123 psk->comment = comment; 125 psk->comment = comment;
124 return (psk); 126 return (psk);
125} 127}
126 128
127/* 129/*
128 * Wipes a private key and frees the associated resources. 130 * Wipes a private key and frees the associated resources.
129 */ 131 */
130static void 132static void
131pam_ssh_free_key(pam_handle_t *pamh __unused, 133pam_ssh_free_key(pam_handle_t *pamh __unused,
132 void *data, int pam_err __unused) 134 void *data, int pam_err __unused)
133{ 135{
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
142PAM_EXTERN int 144PAM_EXTERN int
143pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, 145pam_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) {
212 pam_set_item(pamh, PAM_AUTHTOK, NULL); 201 pam_set_item(pamh, PAM_AUTHTOK, NULL);
213 pass = 0; 202 pass = 0;
214 goto load_keys; 203 goto load_keys;
215 } 204 }
216 205
217 /* switch back to arbitrator credentials before returning */ 206 /* switch back to arbitrator credentials before returning */
218 openpam_restore_cred(pamh); 207 openpam_restore_cred(pamh);
219 208
220 /* no keys? */ 209 /* no keys? */
221 if (nkeys == 0) 210 if (nkeys == 0)
222 return (PAM_AUTH_ERR); 211 return (PAM_AUTH_ERR);
223 212
224 pam_set_data(pamh, pam_ssh_have_keys, NULL, NULL); 213 pam_set_data(pamh, pam_ssh_have_keys, NULL, NULL);
225 return (PAM_SUCCESS); 214 return (PAM_SUCCESS);
226} 215}
227 216
228PAM_EXTERN int 217PAM_EXTERN int
229pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, 218pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused,
230 int argc __unused, const char *argv[] __unused) 219 int argc __unused, const char *argv[] __unused)
231{ 220{
232 221
233 return (PAM_SUCCESS); 222 return (PAM_SUCCESS);
234} 223}
235 224
236/* 225/*
237 * Parses a line from ssh-agent's output. 226 * Parses a line from ssh-agent's output.
238 */ 227 */
239static void 228static void
240pam_ssh_process_agent_output(pam_handle_t *pamh, FILE *f) 229pam_ssh_process_agent_output(pam_handle_t *pamh, FILE *f)
241{ 230{
242 char *line, *p, *key, *val; 231 char *line, *p, *key, *val;
243 size_t len; 232 size_t len;
244 233
245 while ((line = fgetln(f, &len)) != NULL) { 234 while ((line = fgetln(f, &len)) != NULL) {
246 if (len < 4 || strncmp(line, "SSH_", 4) != 0) 235 if (len < 4 || strncmp(line, "SSH_", 4) != 0)
247 continue; 236 continue;
248 237
249 /* find equal sign at end of key */ 238 /* find equal sign at end of key */
250 for (p = key = line; p < line + len; ++p) 239 for (p = key = line; p < line + len; ++p)
251 if (*p == '=') 240 if (*p == '=')
252 break; 241 break;
253 if (p == line + len || *p != '=') 242 if (p == line + len || *p != '=')
254 continue; 243 continue;
255 *p = '\0'; 244 *p = '\0';
256 245
257 /* find semicolon at end of value */ 246 /* find semicolon at end of value */
258 for (val = ++p; p < line + len; ++p) 247 for (val = ++p; p < line + len; ++p)
259 if (*p == ';') 248 if (*p == ';')
260 break; 249 break;
261 if (p == line + len || *p != ';') 250 if (p == line + len || *p != ';')
262 continue; 251 continue;
263 *p = '\0'; 252 *p = '\0';
264 253
265 /* store key-value pair in environment */ 254 /* store key-value pair in environment */
266 openpam_log(PAM_LOG_DEBUG, "got %s: %s", key, val); 255 openpam_log(PAM_LOG_DEBUG, "got %s: %s", key, val);
267 pam_setenv(pamh, key, val, 1); 256 pam_setenv(pamh, key, val, 1);
268 } 257 }
269} 258}
270 259
271/* 260/*
272 * Starts an ssh agent and stores the environment variables derived from 261 * Starts an ssh agent and stores the environment variables derived from
273 * its output. 262 * its output.
274 */ 263 */
275static int 264static int
276pam_ssh_start_agent(pam_handle_t *pamh, struct passwd *pwd) 265pam_ssh_start_agent(pam_handle_t *pamh, struct passwd *pwd)
277{ 266{
278 int agent_pipe[2]; 267 int agent_pipe[2];
279 pid_t pid; 268 pid_t pid;
280 FILE *f; 269 FILE *f;
281 270
282 /* get a pipe which we will use to read the agent's output */ 271 /* get a pipe which we will use to read the agent's output */
283 if (pipe(agent_pipe) == -1) 272 if (pipe(agent_pipe) == -1)
284 return (PAM_SYSTEM_ERR); 273 return (PAM_SYSTEM_ERR);
285 274
286 /* start the agent */ 275 /* start the agent */
287 openpam_log(PAM_LOG_DEBUG, "starting an ssh agent"); 276 openpam_log(PAM_LOG_DEBUG, "starting an ssh agent");
288 pid = fork(); 277 pid = fork();
289 if (pid == (pid_t)-1) { 278 if (pid == (pid_t)-1) {
290 /* failed */ 279 /* failed */
291 close(agent_pipe[0]); 280 close(agent_pipe[0]);
292 close(agent_pipe[1]); 281 close(agent_pipe[1]);
293 return (PAM_SYSTEM_ERR); 282 return (PAM_SYSTEM_ERR);
294 } 283 }
295 if (pid == 0) { 284 if (pid == 0) {
296#ifndef F_CLOSEM 285#ifndef F_CLOSEM
297 int fd; 286 int fd;
298#endif 287#endif
299 /* child: drop privs, close fds and start agent */ 288 /* child: drop privs, close fds and start agent */
300 if (setgid(pwd->pw_gid) == -1) { 289 if (setgid(pwd->pw_gid) == -1) {
301 openpam_log(PAM_LOG_DEBUG, "%s: Cannot setgid %d (%m)", 290 openpam_log(PAM_LOG_DEBUG, "%s: Cannot setgid %d (%m)",
302 __func__, (int)pwd->pw_gid); 291 __func__, (int)pwd->pw_gid);
303 goto done; 292 goto done;
304 } 293 }
305 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) { 294 if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
306 openpam_log(PAM_LOG_DEBUG, 295 openpam_log(PAM_LOG_DEBUG,
307 "%s: Cannot initgroups for %s (%m)", 296 "%s: Cannot initgroups for %s (%m)",
308 __func__, pwd->pw_name); 297 __func__, pwd->pw_name);
309 goto done; 298 goto done;
310 } 299 }
311 if (setuid(pwd->pw_uid) == -1) { 300 if (setuid(pwd->pw_uid) == -1) {
312 openpam_log(PAM_LOG_DEBUG, "%s: Cannot setuid %d (%m)", 301 openpam_log(PAM_LOG_DEBUG, "%s: Cannot setuid %d (%m)",
313 __func__, (int)pwd->pw_uid); 302 __func__, (int)pwd->pw_uid);
314 goto done; 303 goto done;
315 } 304 }
316 (void)close(STDIN_FILENO); 305 (void)close(STDIN_FILENO);
317 (void)open(_PATH_DEVNULL, O_RDONLY); 306 (void)open(_PATH_DEVNULL, O_RDONLY);
318 (void)dup2(agent_pipe[1], STDOUT_FILENO); 307 (void)dup2(agent_pipe[1], STDOUT_FILENO);
319 (void)dup2(agent_pipe[1], STDERR_FILENO); 308 (void)dup2(agent_pipe[1], STDERR_FILENO);
320#ifdef F_CLOSEM 309#ifdef F_CLOSEM
321 (void)fcntl(3, F_CLOSEM, 0); 310 (void)fcntl(3, F_CLOSEM, 0);
322#else 311#else
323 for (fd = 3; fd < getdtablesize(); ++fd) 312 for (fd = 3; fd < getdtablesize(); ++fd)
324 (void)close(fd); 313 (void)close(fd);
325#endif 314#endif
326 (void)execve(pam_ssh_agent, 315 (void)execve(pam_ssh_agent,
327 (char **)__UNCONST(pam_ssh_agent_argv), 316 (char **)__UNCONST(pam_ssh_agent_argv),
328 (char **)__UNCONST(pam_ssh_agent_envp)); 317 (char **)__UNCONST(pam_ssh_agent_envp));
329done: 318done:
330 _exit(127); 319 _exit(127);
331 } 320 }
332 321
333 /* parent */ 322 /* parent */
334 close(agent_pipe[1]); 323 close(agent_pipe[1]);
335 if ((f = fdopen(agent_pipe[0], "r")) == NULL) 324 if ((f = fdopen(agent_pipe[0], "r")) == NULL)
336 return (PAM_SYSTEM_ERR); 325 return (PAM_SYSTEM_ERR);
337 pam_ssh_process_agent_output(pamh, f); 326 pam_ssh_process_agent_output(pamh, f);
338 fclose(f); 327 fclose(f);
339 328
340 return (PAM_SUCCESS); 329 return (PAM_SUCCESS);
341} 330}
342 331
343/* 332/*
344 * Adds previously stored keys to a running agent. 333 * Adds previously stored keys to a running agent.
345 */ 334 */
346static int 335static int
347pam_ssh_add_keys_to_agent(pam_handle_t *pamh) 336pam_ssh_add_keys_to_agent(pam_handle_t *pamh)
348{ 337{
349 AuthenticationConnection *ac; 338 AuthenticationConnection *ac;
350 const struct pam_ssh_key *psk; 339 const struct pam_ssh_key *psk;
351 const char **kfn; 340 const char **kfn;
352 char **envlist, **env; 341 char **envlist, **env;
353 int pam_err; 342 int pam_err;
354 343
355 /* switch to PAM environment */ 344 /* switch to PAM environment */
356 envlist = environ; 345 envlist = environ;
357 if ((environ = pam_getenvlist(pamh)) == NULL) { 346 if ((environ = pam_getenvlist(pamh)) == NULL) {
358 openpam_log(PAM_LOG_DEBUG, "%s: cannot get envlist", 347 openpam_log(PAM_LOG_DEBUG, "%s: cannot get envlist",
359 __func__); 348 __func__);
360 environ = envlist; 349 environ = envlist;
361 return (PAM_SYSTEM_ERR); 350 return (PAM_SYSTEM_ERR);
362 } 351 }
363 352
364 /* get a connection to the agent */ 353 /* get a connection to the agent */
365 if ((ac = ssh_get_authentication_connection()) == NULL) { 354 if ((ac = ssh_get_authentication_connection()) == NULL) {
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)
393 ssh_close_authentication_connection(ac); 382 ssh_close_authentication_connection(ac);
394 383
395 /* switch back to original environment */ 384 /* switch back to original environment */
396 for (env = environ; *env != NULL; ++env) 385 for (env = environ; *env != NULL; ++env)
397 free(*env); 386 free(*env);
398 free(environ); 387 free(environ);
399 environ = envlist; 388 environ = envlist;
400 389
401 return (pam_err); 390 return (pam_err);
402} 391}
403 392
404PAM_EXTERN int 393PAM_EXTERN int
405pam_sm_open_session(pam_handle_t *pamh, int flags __unused, 394pam_sm_open_session(pam_handle_t *pamh, int flags __unused,
406 int argc __unused, const char *argv[] __unused) 395 int argc __unused, const char *argv[] __unused)
407{ 396{
408 struct passwd *pwd, pwres; 397 struct passwd *pwd, pwres;
409 const char *user; 398 const char *user;
410 const void *data; 399 const void *data;
411 int pam_err = PAM_SUCCESS; 400 int pam_err = PAM_SUCCESS;
412 char pwbuf[1024]; 401 char pwbuf[1024];
413 402
414 /* no keys, no work */ 403 /* no keys, no work */
415 if (pam_get_data(pamh, pam_ssh_have_keys, &data) != PAM_SUCCESS && 404 if (pam_get_data(pamh, pam_ssh_have_keys, &data) != PAM_SUCCESS &&
416 openpam_get_option(pamh, "want_agent") == NULL) 405 openpam_get_option(pamh, "want_agent") == NULL)
417 return (PAM_SUCCESS); 406 return (PAM_SUCCESS);
418 407
419 /* switch to user credentials */ 408 /* switch to user credentials */
420 pam_err = pam_get_user(pamh, &user, NULL); 409 pam_err = pam_get_user(pamh, &user, NULL);
421 if (pam_err != PAM_SUCCESS) 410 if (pam_err != PAM_SUCCESS)
422 return (pam_err); 411 return (pam_err);
423 if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || 412 if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
424 pwd == NULL) 413 pwd == NULL)
425 return (PAM_USER_UNKNOWN); 414 return (PAM_USER_UNKNOWN);
426 415
427 /* start the agent */ 416 /* start the agent */
428 pam_err = pam_ssh_start_agent(pamh, pwd); 417 pam_err = pam_ssh_start_agent(pamh, pwd);
429 if (pam_err != PAM_SUCCESS) 418 if (pam_err != PAM_SUCCESS)
430 return pam_err; 419 return pam_err;
431 420
432 pam_err = openpam_borrow_cred(pamh, pwd); 421 pam_err = openpam_borrow_cred(pamh, pwd);
433 if (pam_err != PAM_SUCCESS) 422 if (pam_err != PAM_SUCCESS)
434 return pam_err; 423 return pam_err;
435 424
436 /* we have an agent, see if we can add any keys to it */ 425 /* we have an agent, see if we can add any keys to it */
437 pam_err = pam_ssh_add_keys_to_agent(pamh); 426 pam_err = pam_ssh_add_keys_to_agent(pamh);
438 if (pam_err != PAM_SUCCESS) { 427 if (pam_err != PAM_SUCCESS) {
439 /* XXX ignore failures */ 428 /* XXX ignore failures */
440 openpam_log(PAM_LOG_DEBUG, "failed adding keys to ssh agent"); 429 openpam_log(PAM_LOG_DEBUG, "failed adding keys to ssh agent");
441 pam_err = PAM_SUCCESS; 430 pam_err = PAM_SUCCESS;
442 } 431 }
443 432
444 openpam_restore_cred(pamh); 433 openpam_restore_cred(pamh);
445 return pam_err; 434 return pam_err;
446} 435}
447 436
448PAM_EXTERN int 437PAM_EXTERN int
449pam_sm_close_session(pam_handle_t *pamh, int flags __unused, 438pam_sm_close_session(pam_handle_t *pamh, int flags __unused,
450 int argc __unused, const char *argv[] __unused) 439 int argc __unused, const char *argv[] __unused)
451{ 440{
452 const char *ssh_agent_pid; 441 const char *ssh_agent_pid;
453 char *end; 442 char *end;
454 int status; 443 int status;
455 pid_t pid; 444 pid_t pid;
456 445
457 if ((ssh_agent_pid = pam_getenv(pamh, "SSH_AGENT_PID")) == NULL) { 446 if ((ssh_agent_pid = pam_getenv(pamh, "SSH_AGENT_PID")) == NULL) {
458 openpam_log(PAM_LOG_DEBUG, "no ssh agent"); 447 openpam_log(PAM_LOG_DEBUG, "no ssh agent");
459 return (PAM_SUCCESS); 448 return (PAM_SUCCESS);
460 } 449 }
461 pid = (pid_t)strtol(ssh_agent_pid, &end, 10); 450 pid = (pid_t)strtol(ssh_agent_pid, &end, 10);
462 if (*ssh_agent_pid == '\0' || *end != '\0') { 451 if (*ssh_agent_pid == '\0' || *end != '\0') {
463 openpam_log(PAM_LOG_DEBUG, "invalid ssh agent pid"); 452 openpam_log(PAM_LOG_DEBUG, "invalid ssh agent pid");
464 return (PAM_SESSION_ERR); 453 return (PAM_SESSION_ERR);
465 } 454 }
466 openpam_log(PAM_LOG_DEBUG, "killing ssh agent %d", (int)pid); 455 openpam_log(PAM_LOG_DEBUG, "killing ssh agent %d", (int)pid);
467 if (kill(pid, SIGTERM) == -1 || 456 if (kill(pid, SIGTERM) == -1 ||
468 (waitpid(pid, &status, 0) == -1 && errno != ECHILD)) 457 (waitpid(pid, &status, 0) == -1 && errno != ECHILD))
469 return (PAM_SYSTEM_ERR); 458 return (PAM_SYSTEM_ERR);
470 return (PAM_SUCCESS); 459 return (PAM_SUCCESS);
471} 460}
472 461
473PAM_MODULE_ENTRY("pam_ssh"); 462PAM_MODULE_ENTRY("pam_ssh");