summaryrefslogtreecommitdiff
path: root/auth-pam.c
diff options
context:
space:
mode:
Diffstat (limited to 'auth-pam.c')
-rw-r--r--auth-pam.c327
1 files changed, 239 insertions, 88 deletions
diff --git a/auth-pam.c b/auth-pam.c
index b9f82a1d4..397f7d3a8 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -31,10 +31,14 @@
31 31
32/* Based on $FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */ 32/* Based on $FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */
33#include "includes.h" 33#include "includes.h"
34RCSID("$Id: auth-pam.c,v 1.72.2.2 2003/09/23 09:24:21 djm Exp $"); 34RCSID("$Id: auth-pam.c,v 1.95 2004/02/17 12:20:08 dtucker Exp $");
35 35
36#ifdef USE_PAM 36#ifdef USE_PAM
37#if defined(HAVE_SECURITY_PAM_APPL_H)
37#include <security/pam_appl.h> 38#include <security/pam_appl.h>
39#elif defined (HAVE_PAM_PAM_APPL_H)
40#include <pam/pam_appl.h>
41#endif
38 42
39#include "auth.h" 43#include "auth.h"
40#include "auth-pam.h" 44#include "auth-pam.h"
@@ -53,22 +57,53 @@ RCSID("$Id: auth-pam.c,v 1.72.2.2 2003/09/23 09:24:21 djm Exp $");
53 57
54extern ServerOptions options; 58extern ServerOptions options;
55extern Buffer loginmsg; 59extern Buffer loginmsg;
56 60extern int compat20;
57#define __unused
58 61
59#ifdef USE_POSIX_THREADS 62#ifdef USE_POSIX_THREADS
60#include <pthread.h> 63#include <pthread.h>
61/* 64/*
62 * Avoid namespace clash when *not* using pthreads for systems *with* 65 * Avoid namespace clash when *not* using pthreads for systems *with*
63 * pthreads, which unconditionally define pthread_t via sys/types.h 66 * pthreads, which unconditionally define pthread_t via sys/types.h
64 * (e.g. Linux) 67 * (e.g. Linux)
65 */ 68 */
66typedef pthread_t sp_pthread_t; 69typedef pthread_t sp_pthread_t;
67#else 70#else
71typedef pid_t sp_pthread_t;
72#endif
73
74struct pam_ctxt {
75 sp_pthread_t pam_thread;
76 int pam_psock;
77 int pam_csock;
78 int pam_done;
79};
80
81static void sshpam_free_ctx(void *);
82static struct pam_ctxt *cleanup_ctxt;
83
84#ifndef USE_POSIX_THREADS
68/* 85/*
69 * Simulate threads with processes. 86 * Simulate threads with processes.
70 */ 87 */
71typedef pid_t sp_pthread_t; 88
89static int sshpam_thread_status = -1;
90static mysig_t sshpam_oldsig;
91
92static void
93sshpam_sigchld_handler(int sig)
94{
95 if (cleanup_ctxt == NULL)
96 return; /* handler called after PAM cleanup, shouldn't happen */
97 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0) == -1)
98 return; /* couldn't wait for process */
99 if (WIFSIGNALED(sshpam_thread_status) &&
100 WTERMSIG(sshpam_thread_status) == SIGTERM)
101 return; /* terminated by pthread_cancel */
102 if (!WIFEXITED(sshpam_thread_status))
103 fatal("PAM: authentication thread exited unexpectedly");
104 if (WEXITSTATUS(sshpam_thread_status) != 0)
105 fatal("PAM: authentication thread exited uncleanly");
106}
72 107
73static void 108static void
74pthread_exit(void *value __unused) 109pthread_exit(void *value __unused)
@@ -91,6 +126,7 @@ pthread_create(sp_pthread_t *thread, const void *attr __unused,
91 _exit(1); 126 _exit(1);
92 default: 127 default:
93 *thread = pid; 128 *thread = pid;
129 sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
94 return (0); 130 return (0);
95 } 131 }
96} 132}
@@ -98,6 +134,7 @@ pthread_create(sp_pthread_t *thread, const void *attr __unused,
98static int 134static int
99pthread_cancel(sp_pthread_t thread) 135pthread_cancel(sp_pthread_t thread)
100{ 136{
137 signal(SIGCHLD, sshpam_oldsig);
101 return (kill(thread, SIGTERM)); 138 return (kill(thread, SIGTERM));
102} 139}
103 140
@@ -106,6 +143,9 @@ pthread_join(sp_pthread_t thread, void **value __unused)
106{ 143{
107 int status; 144 int status;
108 145
146 if (sshpam_thread_status != -1)
147 return (sshpam_thread_status);
148 signal(SIGCHLD, sshpam_oldsig);
109 waitpid(thread, &status, 0); 149 waitpid(thread, &status, 0);
110 return (status); 150 return (status);
111} 151}
@@ -115,18 +155,80 @@ pthread_join(sp_pthread_t thread, void **value __unused)
115static pam_handle_t *sshpam_handle = NULL; 155static pam_handle_t *sshpam_handle = NULL;
116static int sshpam_err = 0; 156static int sshpam_err = 0;
117static int sshpam_authenticated = 0; 157static int sshpam_authenticated = 0;
118static int sshpam_new_authtok_reqd = 0;
119static int sshpam_session_open = 0; 158static int sshpam_session_open = 0;
120static int sshpam_cred_established = 0; 159static int sshpam_cred_established = 0;
160static int sshpam_account_status = -1;
161static char **sshpam_env = NULL;
162static int *force_pwchange;
163
164/* Some PAM implementations don't implement this */
165#ifndef HAVE_PAM_GETENVLIST
166static char **
167pam_getenvlist(pam_handle_t *pamh)
168{
169 /*
170 * XXX - If necessary, we can still support envrionment passing
171 * for platforms without pam_getenvlist by searching for known
172 * env vars (e.g. KRB5CCNAME) from the PAM environment.
173 */
174 return NULL;
175}
176#endif
121 177
122struct pam_ctxt { 178void
123 sp_pthread_t pam_thread; 179pam_password_change_required(int reqd)
124 int pam_psock; 180{
125 int pam_csock; 181 debug3("%s %d", __func__, reqd);
126 int pam_done; 182 *force_pwchange = reqd;
127}; 183 if (reqd) {
184 no_port_forwarding_flag |= 2;
185 no_agent_forwarding_flag |= 2;
186 no_x11_forwarding_flag |= 2;
187 } else {
188 no_port_forwarding_flag &= ~2;
189 no_agent_forwarding_flag &= ~2;
190 no_x11_forwarding_flag &= ~2;
191 }
192}
128 193
129static void sshpam_free_ctx(void *); 194/* Import regular and PAM environment from subprocess */
195static void
196import_environments(Buffer *b)
197{
198 char *env;
199 u_int i, num_env;
200 int err;
201
202 debug3("PAM: %s entering", __func__);
203
204 /* Import variables set by do_pam_account */
205 sshpam_account_status = buffer_get_int(b);
206 pam_password_change_required(buffer_get_int(b));
207
208 /* Import environment from subprocess */
209 num_env = buffer_get_int(b);
210 sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env));
211 debug3("PAM: num env strings %d", num_env);
212 for(i = 0; i < num_env; i++)
213 sshpam_env[i] = buffer_get_string(b, NULL);
214
215 sshpam_env[num_env] = NULL;
216
217 /* Import PAM environment from subprocess */
218 num_env = buffer_get_int(b);
219 debug("PAM: num PAM env strings %d", num_env);
220 for(i = 0; i < num_env; i++) {
221 env = buffer_get_string(b, NULL);
222
223#ifdef HAVE_PAM_PUTENV
224 /* Errors are not fatal here */
225 if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
226 error("PAM: pam_putenv: %s",
227 pam_strerror(sshpam_handle, sshpam_err));
228 }
229#endif
230 }
231}
130 232
131/* 233/*
132 * Conversation function for authentication thread. 234 * Conversation function for authentication thread.
@@ -140,6 +242,7 @@ sshpam_thread_conv(int n, const struct pam_message **msg,
140 struct pam_response *reply; 242 struct pam_response *reply;
141 int i; 243 int i;
142 244
245 debug3("PAM: %s entering, %d messages", __func__, n);
143 *resp = NULL; 246 *resp = NULL;
144 247
145 ctxt = data; 248 ctxt = data;
@@ -154,36 +257,42 @@ sshpam_thread_conv(int n, const struct pam_message **msg,
154 for (i = 0; i < n; ++i) { 257 for (i = 0; i < n; ++i) {
155 switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 258 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
156 case PAM_PROMPT_ECHO_OFF: 259 case PAM_PROMPT_ECHO_OFF:
157 buffer_put_cstring(&buffer, 260 buffer_put_cstring(&buffer,
158 PAM_MSG_MEMBER(msg, i, msg)); 261 PAM_MSG_MEMBER(msg, i, msg));
159 ssh_msg_send(ctxt->pam_csock, 262 if (ssh_msg_send(ctxt->pam_csock,
160 PAM_MSG_MEMBER(msg, i, msg_style), &buffer); 263 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
161 ssh_msg_recv(ctxt->pam_csock, &buffer); 264 goto fail;
265 if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
266 goto fail;
162 if (buffer_get_char(&buffer) != PAM_AUTHTOK) 267 if (buffer_get_char(&buffer) != PAM_AUTHTOK)
163 goto fail; 268 goto fail;
164 reply[i].resp = buffer_get_string(&buffer, NULL); 269 reply[i].resp = buffer_get_string(&buffer, NULL);
165 break; 270 break;
166 case PAM_PROMPT_ECHO_ON: 271 case PAM_PROMPT_ECHO_ON:
167 buffer_put_cstring(&buffer, 272 buffer_put_cstring(&buffer,
168 PAM_MSG_MEMBER(msg, i, msg)); 273 PAM_MSG_MEMBER(msg, i, msg));
169 ssh_msg_send(ctxt->pam_csock, 274 if (ssh_msg_send(ctxt->pam_csock,
170 PAM_MSG_MEMBER(msg, i, msg_style), &buffer); 275 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
171 ssh_msg_recv(ctxt->pam_csock, &buffer); 276 goto fail;
277 if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
278 goto fail;
172 if (buffer_get_char(&buffer) != PAM_AUTHTOK) 279 if (buffer_get_char(&buffer) != PAM_AUTHTOK)
173 goto fail; 280 goto fail;
174 reply[i].resp = buffer_get_string(&buffer, NULL); 281 reply[i].resp = buffer_get_string(&buffer, NULL);
175 break; 282 break;
176 case PAM_ERROR_MSG: 283 case PAM_ERROR_MSG:
177 buffer_put_cstring(&buffer, 284 buffer_put_cstring(&buffer,
178 PAM_MSG_MEMBER(msg, i, msg)); 285 PAM_MSG_MEMBER(msg, i, msg));
179 ssh_msg_send(ctxt->pam_csock, 286 if (ssh_msg_send(ctxt->pam_csock,
180 PAM_MSG_MEMBER(msg, i, msg_style), &buffer); 287 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
288 goto fail;
181 break; 289 break;
182 case PAM_TEXT_INFO: 290 case PAM_TEXT_INFO:
183 buffer_put_cstring(&buffer, 291 buffer_put_cstring(&buffer,
184 PAM_MSG_MEMBER(msg, i, msg)); 292 PAM_MSG_MEMBER(msg, i, msg));
185 ssh_msg_send(ctxt->pam_csock, 293 if (ssh_msg_send(ctxt->pam_csock,
186 PAM_MSG_MEMBER(msg, i, msg_style), &buffer); 294 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
295 goto fail;
187 break; 296 break;
188 default: 297 default:
189 goto fail; 298 goto fail;
@@ -214,10 +323,14 @@ sshpam_thread(void *ctxtp)
214 Buffer buffer; 323 Buffer buffer;
215 struct pam_conv sshpam_conv; 324 struct pam_conv sshpam_conv;
216#ifndef USE_POSIX_THREADS 325#ifndef USE_POSIX_THREADS
326 extern char **environ;
327 char **env_from_pam;
328 u_int i;
217 const char *pam_user; 329 const char *pam_user;
218 330
219 pam_get_item(sshpam_handle, PAM_USER, (const void **)&pam_user); 331 pam_get_item(sshpam_handle, PAM_USER, (const void **)&pam_user);
220 setproctitle("%s [pam]", pam_user); 332 setproctitle("%s [pam]", pam_user);
333 environ[0] = NULL;
221#endif 334#endif
222 335
223 sshpam_conv.conv = sshpam_thread_conv; 336 sshpam_conv.conv = sshpam_thread_conv;
@@ -231,7 +344,43 @@ sshpam_thread(void *ctxtp)
231 sshpam_err = pam_authenticate(sshpam_handle, 0); 344 sshpam_err = pam_authenticate(sshpam_handle, 0);
232 if (sshpam_err != PAM_SUCCESS) 345 if (sshpam_err != PAM_SUCCESS)
233 goto auth_fail; 346 goto auth_fail;
347
348 if (compat20) {
349 if (!do_pam_account())
350 goto auth_fail;
351 if (*force_pwchange) {
352 sshpam_err = pam_chauthtok(sshpam_handle,
353 PAM_CHANGE_EXPIRED_AUTHTOK);
354 if (sshpam_err != PAM_SUCCESS)
355 goto auth_fail;
356 pam_password_change_required(0);
357 }
358 }
359
234 buffer_put_cstring(&buffer, "OK"); 360 buffer_put_cstring(&buffer, "OK");
361
362#ifndef USE_POSIX_THREADS
363 /* Export variables set by do_pam_account */
364 buffer_put_int(&buffer, sshpam_account_status);
365 buffer_put_int(&buffer, *force_pwchange);
366
367 /* Export any environment strings set in child */
368 for(i = 0; environ[i] != NULL; i++)
369 ; /* Count */
370 buffer_put_int(&buffer, i);
371 for(i = 0; environ[i] != NULL; i++)
372 buffer_put_cstring(&buffer, environ[i]);
373
374 /* Export any environment strings set by PAM in child */
375 env_from_pam = pam_getenvlist(sshpam_handle);
376 for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
377 ; /* Count */
378 buffer_put_int(&buffer, i);
379 for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
380 buffer_put_cstring(&buffer, env_from_pam[i]);
381#endif /* USE_POSIX_THREADS */
382
383 /* XXX - can't do much about an error here */
235 ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer); 384 ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
236 buffer_free(&buffer); 385 buffer_free(&buffer);
237 pthread_exit(NULL); 386 pthread_exit(NULL);
@@ -239,37 +388,43 @@ sshpam_thread(void *ctxtp)
239 auth_fail: 388 auth_fail:
240 buffer_put_cstring(&buffer, 389 buffer_put_cstring(&buffer,
241 pam_strerror(sshpam_handle, sshpam_err)); 390 pam_strerror(sshpam_handle, sshpam_err));
391 /* XXX - can't do much about an error here */
242 ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); 392 ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
243 buffer_free(&buffer); 393 buffer_free(&buffer);
244 pthread_exit(NULL); 394 pthread_exit(NULL);
245 395
246 return (NULL); /* Avoid warning for non-pthread case */ 396 return (NULL); /* Avoid warning for non-pthread case */
247} 397}
248 398
249static void 399void
250sshpam_thread_cleanup(void *ctxtp) 400sshpam_thread_cleanup(void)
251{ 401{
252 struct pam_ctxt *ctxt = ctxtp; 402 struct pam_ctxt *ctxt = cleanup_ctxt;
253 403
254 pthread_cancel(ctxt->pam_thread); 404 debug3("PAM: %s entering", __func__);
255 pthread_join(ctxt->pam_thread, NULL); 405 if (ctxt != NULL && ctxt->pam_thread != 0) {
256 close(ctxt->pam_psock); 406 pthread_cancel(ctxt->pam_thread);
257 close(ctxt->pam_csock); 407 pthread_join(ctxt->pam_thread, NULL);
408 close(ctxt->pam_psock);
409 close(ctxt->pam_csock);
410 memset(ctxt, 0, sizeof(*ctxt));
411 cleanup_ctxt = NULL;
412 }
258} 413}
259 414
260static int 415static int
261sshpam_null_conv(int n, const struct pam_message **msg, 416sshpam_null_conv(int n, const struct pam_message **msg,
262 struct pam_response **resp, void *data) 417 struct pam_response **resp, void *data)
263{ 418{
419 debug3("PAM: %s entering, %d messages", __func__, n);
264 return (PAM_CONV_ERR); 420 return (PAM_CONV_ERR);
265} 421}
266 422
267static struct pam_conv null_conv = { sshpam_null_conv, NULL }; 423static struct pam_conv null_conv = { sshpam_null_conv, NULL };
268 424
269static void 425void
270sshpam_cleanup(void *arg) 426sshpam_cleanup(void)
271{ 427{
272 (void)arg;
273 debug("PAM: cleanup"); 428 debug("PAM: cleanup");
274 if (sshpam_handle == NULL) 429 if (sshpam_handle == NULL)
275 return; 430 return;
@@ -282,7 +437,7 @@ sshpam_cleanup(void *arg)
282 pam_close_session(sshpam_handle, PAM_SILENT); 437 pam_close_session(sshpam_handle, PAM_SILENT);
283 sshpam_session_open = 0; 438 sshpam_session_open = 0;
284 } 439 }
285 sshpam_authenticated = sshpam_new_authtok_reqd = 0; 440 sshpam_authenticated = 0;
286 pam_end(sshpam_handle, sshpam_err); 441 pam_end(sshpam_handle, sshpam_err);
287 sshpam_handle = NULL; 442 sshpam_handle = NULL;
288} 443}
@@ -300,7 +455,6 @@ sshpam_init(const char *user)
300 PAM_USER, (const void **)&pam_user); 455 PAM_USER, (const void **)&pam_user);
301 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) 456 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
302 return (0); 457 return (0);
303 fatal_remove_cleanup(sshpam_cleanup, NULL);
304 pam_end(sshpam_handle, sshpam_err); 458 pam_end(sshpam_handle, sshpam_err);
305 sshpam_handle = NULL; 459 sshpam_handle = NULL;
306 } 460 }
@@ -321,11 +475,11 @@ sshpam_init(const char *user)
321 return (-1); 475 return (-1);
322 } 476 }
323#ifdef PAM_TTY_KLUDGE 477#ifdef PAM_TTY_KLUDGE
324 /* 478 /*
325 * Some silly PAM modules (e.g. pam_time) require a TTY to operate. 479 * Some silly PAM modules (e.g. pam_time) require a TTY to operate.
326 * sshd doesn't set the tty until too late in the auth process and 480 * sshd doesn't set the tty until too late in the auth process and
327 * may not even set one (for tty-less connections) 481 * may not even set one (for tty-less connections)
328 */ 482 */
329 debug("PAM: setting PAM_TTY to \"ssh\""); 483 debug("PAM: setting PAM_TTY to \"ssh\"");
330 sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh"); 484 sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
331 if (sshpam_err != PAM_SUCCESS) { 485 if (sshpam_err != PAM_SUCCESS) {
@@ -334,7 +488,6 @@ sshpam_init(const char *user)
334 return (-1); 488 return (-1);
335 } 489 }
336#endif 490#endif
337 fatal_add_cleanup(sshpam_cleanup, NULL);
338 return (0); 491 return (0);
339} 492}
340 493
@@ -344,6 +497,7 @@ sshpam_init_ctx(Authctxt *authctxt)
344 struct pam_ctxt *ctxt; 497 struct pam_ctxt *ctxt;
345 int socks[2]; 498 int socks[2];
346 499
500 debug3("PAM: %s entering", __func__);
347 /* Refuse to start if we don't have PAM enabled */ 501 /* Refuse to start if we don't have PAM enabled */
348 if (!options.use_pam) 502 if (!options.use_pam)
349 return NULL; 503 return NULL;
@@ -355,7 +509,9 @@ sshpam_init_ctx(Authctxt *authctxt)
355 } 509 }
356 510
357 ctxt = xmalloc(sizeof *ctxt); 511 ctxt = xmalloc(sizeof *ctxt);
358 ctxt->pam_done = 0; 512 memset(ctxt, 0, sizeof(*ctxt));
513
514 force_pwchange = &(authctxt->force_pwchange);
359 515
360 /* Start the authentication thread */ 516 /* Start the authentication thread */
361 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { 517 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
@@ -373,7 +529,7 @@ sshpam_init_ctx(Authctxt *authctxt)
373 xfree(ctxt); 529 xfree(ctxt);
374 return (NULL); 530 return (NULL);
375 } 531 }
376 fatal_add_cleanup(sshpam_thread_cleanup, ctxt); 532 cleanup_ctxt = ctxt;
377 return (ctxt); 533 return (ctxt);
378} 534}
379 535
@@ -388,6 +544,7 @@ sshpam_query(void *ctx, char **name, char **info,
388 char *msg; 544 char *msg;
389 size_t len; 545 size_t len;
390 546
547 debug3("PAM: %s entering", __func__);
391 buffer_init(&buffer); 548 buffer_init(&buffer);
392 *name = xstrdup(""); 549 *name = xstrdup("");
393 *info = xstrdup(""); 550 *info = xstrdup("");
@@ -427,6 +584,7 @@ sshpam_query(void *ctx, char **name, char **info,
427 **prompts = NULL; 584 **prompts = NULL;
428 } 585 }
429 if (type == PAM_SUCCESS) { 586 if (type == PAM_SUCCESS) {
587 import_environments(&buffer);
430 *num = 0; 588 *num = 0;
431 **echo_on = 0; 589 **echo_on = 0;
432 ctxt->pam_done = 1; 590 ctxt->pam_done = 1;
@@ -434,6 +592,7 @@ sshpam_query(void *ctx, char **name, char **info,
434 return (0); 592 return (0);
435 } 593 }
436 error("PAM: %s", msg); 594 error("PAM: %s", msg);
595 /* FALLTHROUGH */
437 default: 596 default:
438 *num = 0; 597 *num = 0;
439 **echo_on = 0; 598 **echo_on = 0;
@@ -452,7 +611,7 @@ sshpam_respond(void *ctx, u_int num, char **resp)
452 Buffer buffer; 611 Buffer buffer;
453 struct pam_ctxt *ctxt = ctx; 612 struct pam_ctxt *ctxt = ctx;
454 613
455 debug2("PAM: %s", __func__); 614 debug2("PAM: %s entering, %d responses", __func__, num);
456 switch (ctxt->pam_done) { 615 switch (ctxt->pam_done) {
457 case 1: 616 case 1:
458 sshpam_authenticated = 1; 617 sshpam_authenticated = 1;
@@ -468,7 +627,10 @@ sshpam_respond(void *ctx, u_int num, char **resp)
468 } 627 }
469 buffer_init(&buffer); 628 buffer_init(&buffer);
470 buffer_put_cstring(&buffer, *resp); 629 buffer_put_cstring(&buffer, *resp);
471 ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer); 630 if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
631 buffer_free(&buffer);
632 return (-1);
633 }
472 buffer_free(&buffer); 634 buffer_free(&buffer);
473 return (1); 635 return (1);
474} 636}
@@ -478,8 +640,8 @@ sshpam_free_ctx(void *ctxtp)
478{ 640{
479 struct pam_ctxt *ctxt = ctxtp; 641 struct pam_ctxt *ctxt = ctxtp;
480 642
481 fatal_remove_cleanup(sshpam_thread_cleanup, ctxt); 643 debug3("PAM: %s entering", __func__);
482 sshpam_thread_cleanup(ctxtp); 644 sshpam_thread_cleanup();
483 xfree(ctxt); 645 xfree(ctxt);
484 /* 646 /*
485 * We don't call sshpam_cleanup() here because we may need the PAM 647 * We don't call sshpam_cleanup() here because we may need the PAM
@@ -521,29 +683,28 @@ start_pam(const char *user)
521void 683void
522finish_pam(void) 684finish_pam(void)
523{ 685{
524 fatal_remove_cleanup(sshpam_cleanup, NULL); 686 sshpam_cleanup();
525 sshpam_cleanup(NULL);
526} 687}
527 688
528u_int 689u_int
529do_pam_account(void) 690do_pam_account(void)
530{ 691{
692 if (sshpam_account_status != -1)
693 return (sshpam_account_status);
694
531 sshpam_err = pam_acct_mgmt(sshpam_handle, 0); 695 sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
532 debug3("%s: pam_acct_mgmt = %d", __func__, sshpam_err); 696 debug3("PAM: %s pam_acct_mgmt = %d", __func__, sshpam_err);
533 697
534 if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) 698 if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
535 return (0); 699 sshpam_account_status = 0;
536 700 return (sshpam_account_status);
537 if (sshpam_err == PAM_NEW_AUTHTOK_REQD) {
538 sshpam_new_authtok_reqd = 1;
539
540 /* Prevent forwardings until password changed */
541 no_port_forwarding_flag |= 2;
542 no_agent_forwarding_flag |= 2;
543 no_x11_forwarding_flag |= 2;
544 } 701 }
545 702
546 return (1); 703 if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
704 pam_password_change_required(1);
705
706 sshpam_account_status = 1;
707 return (sshpam_account_status);
547} 708}
548 709
549void 710void
@@ -585,12 +746,6 @@ do_pam_setcred(int init)
585 pam_strerror(sshpam_handle, sshpam_err)); 746 pam_strerror(sshpam_handle, sshpam_err));
586} 747}
587 748
588int
589is_pam_password_change_required(void)
590{
591 return (sshpam_new_authtok_reqd);
592}
593
594static int 749static int
595pam_tty_conv(int n, const struct pam_message **msg, 750pam_tty_conv(int n, const struct pam_message **msg,
596 struct pam_response **resp, void *data) 751 struct pam_response **resp, void *data)
@@ -599,6 +754,8 @@ pam_tty_conv(int n, const struct pam_message **msg,
599 struct pam_response *reply; 754 struct pam_response *reply;
600 int i; 755 int i;
601 756
757 debug3("PAM: %s called with %d messages", __func__, n);
758
602 *resp = NULL; 759 *resp = NULL;
603 760
604 if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO)) 761 if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
@@ -612,7 +769,7 @@ pam_tty_conv(int n, const struct pam_message **msg,
612 switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 769 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
613 case PAM_PROMPT_ECHO_OFF: 770 case PAM_PROMPT_ECHO_OFF:
614 reply[i].resp = 771 reply[i].resp =
615 read_passphrase(PAM_MSG_MEMBER(msg, i, msg), 772 read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
616 RP_ALLOW_STDIN); 773 RP_ALLOW_STDIN);
617 reply[i].resp_retcode = PAM_SUCCESS; 774 reply[i].resp_retcode = PAM_SUCCESS;
618 break; 775 break;
@@ -715,7 +872,7 @@ void
715do_pam_session(void) 872do_pam_session(void)
716{ 873{
717 debug3("PAM: opening session"); 874 debug3("PAM: opening session");
718 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 875 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
719 (const void *)&store_conv); 876 (const void *)&store_conv);
720 if (sshpam_err != PAM_SUCCESS) 877 if (sshpam_err != PAM_SUCCESS)
721 fatal("PAM: failed to set PAM_CONV: %s", 878 fatal("PAM: failed to set PAM_CONV: %s",
@@ -727,17 +884,16 @@ do_pam_session(void)
727 sshpam_session_open = 1; 884 sshpam_session_open = 1;
728} 885}
729 886
730/* 887/*
731 * Set a PAM environment string. We need to do this so that the session 888 * Set a PAM environment string. We need to do this so that the session
732 * modules can handle things like Kerberos/GSI credentials that appear 889 * modules can handle things like Kerberos/GSI credentials that appear
733 * during the ssh authentication process. 890 * during the ssh authentication process.
734 */ 891 */
735
736int 892int
737do_pam_putenv(char *name, char *value) 893do_pam_putenv(char *name, char *value)
738{ 894{
739 int ret = 1; 895 int ret = 1;
740#ifdef HAVE_PAM_PUTENV 896#ifdef HAVE_PAM_PUTENV
741 char *compound; 897 char *compound;
742 size_t len; 898 size_t len;
743 899
@@ -752,21 +908,16 @@ do_pam_putenv(char *name, char *value)
752 return (ret); 908 return (ret);
753} 909}
754 910
755void 911char **
756print_pam_messages(void) 912fetch_pam_child_environment(void)
757{ 913{
758 /* XXX */ 914 return sshpam_env;
759} 915}
760 916
761char ** 917char **
762fetch_pam_environment(void) 918fetch_pam_environment(void)
763{ 919{
764#ifdef HAVE_PAM_GETENVLIST
765 debug("PAM: retrieving environment");
766 return (pam_getenvlist(sshpam_handle)); 920 return (pam_getenvlist(sshpam_handle));
767#else
768 return (NULL);
769#endif
770} 921}
771 922
772void 923void