Deleted Added
full compact
auth-pam.c (157019) auth-pam.c (162856)
1/*-
2 * Copyright (c) 2002 Networks Associates Technology, Inc.
3 * All rights reserved.
4 *
5 * This software was developed for the FreeBSD Project by ThinkSec AS and
6 * NAI Labs, the Security Research Division of Network Associates, Inc.
7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
8 * DARPA CHATS research program.

--- 33 unchanged lines hidden (view full) ---

42 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
43 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
44 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
45 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 */
47
48/* Based on $xFreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */
49#include "includes.h"
1/*-
2 * Copyright (c) 2002 Networks Associates Technology, Inc.
3 * All rights reserved.
4 *
5 * This software was developed for the FreeBSD Project by ThinkSec AS and
6 * NAI Labs, the Security Research Division of Network Associates, Inc.
7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
8 * DARPA CHATS research program.

--- 33 unchanged lines hidden (view full) ---

42 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
43 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
44 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
45 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 */
47
48/* Based on $xFreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */
49#include "includes.h"
50RCSID("$Id: auth-pam.c,v 1.128 2006/01/29 05:46:13 dtucker Exp $");
51RCSID("$FreeBSD: head/crypto/openssh/auth-pam.c 157019 2006-03-22 20:41:37Z des $");
50__RCSID("$FreeBSD: head/crypto/openssh/auth-pam.c 162856 2006-09-30 13:38:06Z des $");
52
51
52#include <sys/types.h>
53#include <sys/stat.h>
54#include <sys/wait.h>
55
56#include <errno.h>
57#include <signal.h>
58#include <stdarg.h>
59#include <string.h>
60#include <unistd.h>
61
53#ifdef USE_PAM
54#if defined(HAVE_SECURITY_PAM_APPL_H)
55#include <security/pam_appl.h>
56#elif defined (HAVE_PAM_PAM_APPL_H)
57#include <pam/pam_appl.h>
58#endif
59
60/* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
61#ifdef PAM_SUN_CODEBASE
62# define sshpam_const /* Solaris, HP-UX, AIX */
63#else
64# define sshpam_const const /* LinuxPAM, OpenPAM */
65#endif
66
62#ifdef USE_PAM
63#if defined(HAVE_SECURITY_PAM_APPL_H)
64#include <security/pam_appl.h>
65#elif defined (HAVE_PAM_PAM_APPL_H)
66#include <pam/pam_appl.h>
67#endif
68
69/* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
70#ifdef PAM_SUN_CODEBASE
71# define sshpam_const /* Solaris, HP-UX, AIX */
72#else
73# define sshpam_const const /* LinuxPAM, OpenPAM */
74#endif
75
76/* Ambiguity in spec: is it an array of pointers or a pointer to an array? */
77#ifdef PAM_SUN_CODEBASE
78# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
79#else
80# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
81#endif
82
83#include "xmalloc.h"
84#include "buffer.h"
85#include "key.h"
86#include "hostfile.h"
67#include "auth.h"
68#include "auth-pam.h"
87#include "auth.h"
88#include "auth-pam.h"
69#include "buffer.h"
70#include "bufaux.h"
71#include "canohost.h"
72#include "log.h"
89#include "canohost.h"
90#include "log.h"
73#include "monitor_wrap.h"
74#include "msg.h"
75#include "packet.h"
76#include "misc.h"
77#include "servconf.h"
78#include "ssh2.h"
91#include "msg.h"
92#include "packet.h"
93#include "misc.h"
94#include "servconf.h"
95#include "ssh2.h"
79#include "xmalloc.h"
80#include "auth-options.h"
96#include "auth-options.h"
97#ifdef GSSAPI
98#include "ssh-gss.h"
99#endif
100#include "monitor_wrap.h"
81
82extern ServerOptions options;
83extern Buffer loginmsg;
84extern int compat20;
85extern u_int utmp_len;
86
87/* so we don't silently change behaviour */
88#ifdef USE_POSIX_THREADS

--- 53 unchanged lines hidden (view full) ---

142 WTERMSIG(sshpam_thread_status) == SIGTERM)
143 return; /* terminated by pthread_cancel */
144 if (!WIFEXITED(sshpam_thread_status))
145 fatal("PAM: authentication thread exited unexpectedly");
146 if (WEXITSTATUS(sshpam_thread_status) != 0)
147 fatal("PAM: authentication thread exited uncleanly");
148}
149
101
102extern ServerOptions options;
103extern Buffer loginmsg;
104extern int compat20;
105extern u_int utmp_len;
106
107/* so we don't silently change behaviour */
108#ifdef USE_POSIX_THREADS

--- 53 unchanged lines hidden (view full) ---

162 WTERMSIG(sshpam_thread_status) == SIGTERM)
163 return; /* terminated by pthread_cancel */
164 if (!WIFEXITED(sshpam_thread_status))
165 fatal("PAM: authentication thread exited unexpectedly");
166 if (WEXITSTATUS(sshpam_thread_status) != 0)
167 fatal("PAM: authentication thread exited uncleanly");
168}
169
170/* ARGSUSED */
150static void
171static void
151pthread_exit(void *value __unused)
172pthread_exit(void *value)
152{
153 _exit(0);
154}
155
173{
174 _exit(0);
175}
176
177/* ARGSUSED */
156static int
178static int
157pthread_create(sp_pthread_t *thread, const void *attr __unused,
179pthread_create(sp_pthread_t *thread, const void *attr,
158 void *(*thread_start)(void *), void *arg)
159{
160 pid_t pid;
161 struct pam_ctxt *ctx = arg;
162
163 sshpam_thread_status = -1;
164 switch ((pid = fork())) {
165 case -1:

--- 15 unchanged lines hidden (view full) ---

181
182static int
183pthread_cancel(sp_pthread_t thread)
184{
185 signal(SIGCHLD, sshpam_oldsig);
186 return (kill(thread, SIGTERM));
187}
188
180 void *(*thread_start)(void *), void *arg)
181{
182 pid_t pid;
183 struct pam_ctxt *ctx = arg;
184
185 sshpam_thread_status = -1;
186 switch ((pid = fork())) {
187 case -1:

--- 15 unchanged lines hidden (view full) ---

203
204static int
205pthread_cancel(sp_pthread_t thread)
206{
207 signal(SIGCHLD, sshpam_oldsig);
208 return (kill(thread, SIGTERM));
209}
210
211/* ARGSUSED */
189static int
212static int
190pthread_join(sp_pthread_t thread, void **value __unused)
213pthread_join(sp_pthread_t thread, void **value)
191{
192 int status;
193
194 if (sshpam_thread_status != -1)
195 return (sshpam_thread_status);
196 signal(SIGCHLD, sshpam_oldsig);
197 waitpid(thread, &status, 0);
198 return (status);

--- 81 unchanged lines hidden (view full) ---

280
281#ifndef UNSUPPORTED_POSIX_THREADS_HACK
282 /* Import variables set by do_pam_account */
283 sshpam_account_status = buffer_get_int(b);
284 sshpam_password_change_required(buffer_get_int(b));
285
286 /* Import environment from subprocess */
287 num_env = buffer_get_int(b);
214{
215 int status;
216
217 if (sshpam_thread_status != -1)
218 return (sshpam_thread_status);
219 signal(SIGCHLD, sshpam_oldsig);
220 waitpid(thread, &status, 0);
221 return (status);

--- 81 unchanged lines hidden (view full) ---

303
304#ifndef UNSUPPORTED_POSIX_THREADS_HACK
305 /* Import variables set by do_pam_account */
306 sshpam_account_status = buffer_get_int(b);
307 sshpam_password_change_required(buffer_get_int(b));
308
309 /* Import environment from subprocess */
310 num_env = buffer_get_int(b);
288 sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env));
311 if (num_env > 1024)
312 fatal("%s: received %u environment variables, expected <= 1024",
313 __func__, num_env);
314 sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
289 debug3("PAM: num env strings %d", num_env);
290 for(i = 0; i < num_env; i++)
291 sshpam_env[i] = buffer_get_string(b, NULL);
292
293 sshpam_env[num_env] = NULL;
294
295 /* Import PAM environment from subprocess */
296 num_env = buffer_get_int(b);

--- 30 unchanged lines hidden (view full) ---

327 if (data == NULL) {
328 error("PAM: conversation function passed a null context");
329 return (PAM_CONV_ERR);
330 }
331 ctxt = data;
332 if (n <= 0 || n > PAM_MAX_NUM_MSG)
333 return (PAM_CONV_ERR);
334
315 debug3("PAM: num env strings %d", num_env);
316 for(i = 0; i < num_env; i++)
317 sshpam_env[i] = buffer_get_string(b, NULL);
318
319 sshpam_env[num_env] = NULL;
320
321 /* Import PAM environment from subprocess */
322 num_env = buffer_get_int(b);

--- 30 unchanged lines hidden (view full) ---

353 if (data == NULL) {
354 error("PAM: conversation function passed a null context");
355 return (PAM_CONV_ERR);
356 }
357 ctxt = data;
358 if (n <= 0 || n > PAM_MAX_NUM_MSG)
359 return (PAM_CONV_ERR);
360
335 if ((reply = malloc(n * sizeof(*reply))) == NULL)
361 if ((reply = calloc(n, sizeof(*reply))) == NULL)
336 return (PAM_CONV_ERR);
362 return (PAM_CONV_ERR);
337 memset(reply, 0, n * sizeof(*reply));
338
339 buffer_init(&buffer);
340 for (i = 0; i < n; ++i) {
341 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
342 case PAM_PROMPT_ECHO_OFF:
343 buffer_put_cstring(&buffer,
344 PAM_MSG_MEMBER(msg, i, msg));
345 if (ssh_msg_send(ctxt->pam_csock,

--- 62 unchanged lines hidden (view full) ---

408 int flags = (options.permit_empty_passwd == 0 ?
409 PAM_DISALLOW_NULL_AUTHTOK : 0);
410#ifndef UNSUPPORTED_POSIX_THREADS_HACK
411 extern char **environ;
412 char **env_from_pam;
413 u_int i;
414 const char *pam_user;
415 const char **ptr_pam_user = &pam_user;
363
364 buffer_init(&buffer);
365 for (i = 0; i < n; ++i) {
366 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
367 case PAM_PROMPT_ECHO_OFF:
368 buffer_put_cstring(&buffer,
369 PAM_MSG_MEMBER(msg, i, msg));
370 if (ssh_msg_send(ctxt->pam_csock,

--- 62 unchanged lines hidden (view full) ---

433 int flags = (options.permit_empty_passwd == 0 ?
434 PAM_DISALLOW_NULL_AUTHTOK : 0);
435#ifndef UNSUPPORTED_POSIX_THREADS_HACK
436 extern char **environ;
437 char **env_from_pam;
438 u_int i;
439 const char *pam_user;
440 const char **ptr_pam_user = &pam_user;
441 char *tz = getenv("TZ");
416
417 pam_get_item(sshpam_handle, PAM_USER,
418 (sshpam_const void **)ptr_pam_user);
442
443 pam_get_item(sshpam_handle, PAM_USER,
444 (sshpam_const void **)ptr_pam_user);
445
419 environ[0] = NULL;
446 environ[0] = NULL;
447 if (tz != NULL)
448 if (setenv("TZ", tz, 1) == -1)
449 error("PAM: could not set TZ environment: %s",
450 strerror(errno));
420
421 if (sshpam_authctxt != NULL) {
422 setproctitle("%s [pam]",
423 sshpam_authctxt->valid ? pam_user : "unknown");
424 }
425#endif
426
427 sshpam_conv.conv = sshpam_thread_conv;

--- 7 unchanged lines hidden (view full) ---

435 (const void *)&sshpam_conv);
436 if (sshpam_err != PAM_SUCCESS)
437 goto auth_fail;
438 sshpam_err = pam_authenticate(sshpam_handle, flags);
439 if (sshpam_err != PAM_SUCCESS)
440 goto auth_fail;
441
442 if (compat20) {
451
452 if (sshpam_authctxt != NULL) {
453 setproctitle("%s [pam]",
454 sshpam_authctxt->valid ? pam_user : "unknown");
455 }
456#endif
457
458 sshpam_conv.conv = sshpam_thread_conv;

--- 7 unchanged lines hidden (view full) ---

466 (const void *)&sshpam_conv);
467 if (sshpam_err != PAM_SUCCESS)
468 goto auth_fail;
469 sshpam_err = pam_authenticate(sshpam_handle, flags);
470 if (sshpam_err != PAM_SUCCESS)
471 goto auth_fail;
472
473 if (compat20) {
443 if (!do_pam_account())
474 if (!do_pam_account()) {
475 sshpam_err = PAM_ACCT_EXPIRED;
444 goto auth_fail;
476 goto auth_fail;
477 }
445 if (sshpam_authctxt->force_pwchange) {
446 sshpam_err = pam_chauthtok(sshpam_handle,
447 PAM_CHANGE_EXPIRED_AUTHTOK);
448 if (sshpam_err != PAM_SUCCESS)
449 goto auth_fail;
450 sshpam_password_change_required(0);
451 }
452 }

--- 25 unchanged lines hidden (view full) ---

478 ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
479 buffer_free(&buffer);
480 pthread_exit(NULL);
481
482 auth_fail:
483 buffer_put_cstring(&buffer,
484 pam_strerror(sshpam_handle, sshpam_err));
485 /* XXX - can't do much about an error here */
478 if (sshpam_authctxt->force_pwchange) {
479 sshpam_err = pam_chauthtok(sshpam_handle,
480 PAM_CHANGE_EXPIRED_AUTHTOK);
481 if (sshpam_err != PAM_SUCCESS)
482 goto auth_fail;
483 sshpam_password_change_required(0);
484 }
485 }

--- 25 unchanged lines hidden (view full) ---

511 ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
512 buffer_free(&buffer);
513 pthread_exit(NULL);
514
515 auth_fail:
516 buffer_put_cstring(&buffer,
517 pam_strerror(sshpam_handle, sshpam_err));
518 /* XXX - can't do much about an error here */
486 ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
519 if (sshpam_err == PAM_ACCT_EXPIRED)
520 ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer);
521 else
522 ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
487 buffer_free(&buffer);
488 pthread_exit(NULL);
489
490 return (NULL); /* Avoid warning for non-pthread case */
491}
492
493void
494sshpam_thread_cleanup(void)

--- 30 unchanged lines hidden (view full) ---

525 size_t len;
526
527 debug3("PAM: %s called with %d messages", __func__, n);
528 *resp = NULL;
529
530 if (n <= 0 || n > PAM_MAX_NUM_MSG)
531 return (PAM_CONV_ERR);
532
523 buffer_free(&buffer);
524 pthread_exit(NULL);
525
526 return (NULL); /* Avoid warning for non-pthread case */
527}
528
529void
530sshpam_thread_cleanup(void)

--- 30 unchanged lines hidden (view full) ---

561 size_t len;
562
563 debug3("PAM: %s called with %d messages", __func__, n);
564 *resp = NULL;
565
566 if (n <= 0 || n > PAM_MAX_NUM_MSG)
567 return (PAM_CONV_ERR);
568
533 if ((reply = malloc(n * sizeof(*reply))) == NULL)
569 if ((reply = calloc(n, sizeof(*reply))) == NULL)
534 return (PAM_CONV_ERR);
570 return (PAM_CONV_ERR);
535 memset(reply, 0, n * sizeof(*reply));
536
537 for (i = 0; i < n; ++i) {
538 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
539 case PAM_ERROR_MSG:
540 case PAM_TEXT_INFO:
541 len = strlen(PAM_MSG_MEMBER(msg, i, msg));
542 buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len);
543 buffer_append(&loginmsg, "\n", 1 );

--- 90 unchanged lines hidden (view full) ---

634
635static void *
636sshpam_init_ctx(Authctxt *authctxt)
637{
638 struct pam_ctxt *ctxt;
639 int socks[2];
640
641 debug3("PAM: %s entering", __func__);
571
572 for (i = 0; i < n; ++i) {
573 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
574 case PAM_ERROR_MSG:
575 case PAM_TEXT_INFO:
576 len = strlen(PAM_MSG_MEMBER(msg, i, msg));
577 buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len);
578 buffer_append(&loginmsg, "\n", 1 );

--- 90 unchanged lines hidden (view full) ---

669
670static void *
671sshpam_init_ctx(Authctxt *authctxt)
672{
673 struct pam_ctxt *ctxt;
674 int socks[2];
675
676 debug3("PAM: %s entering", __func__);
642 /* Refuse to start if we don't have PAM enabled */
643 if (!options.use_pam)
677 /*
678 * Refuse to start if we don't have PAM enabled or do_pam_account
679 * has previously failed.
680 */
681 if (!options.use_pam || sshpam_account_status == 0)
644 return NULL;
645
646 /* Initialize PAM */
647 if (sshpam_init(authctxt) == -1) {
648 error("PAM: initialization failed");
649 return (NULL);
650 }
651

--- 43 unchanged lines hidden (view full) ---

695 type = buffer_get_char(&buffer);
696 msg = buffer_get_string(&buffer, NULL);
697 mlen = strlen(msg);
698 switch (type) {
699 case PAM_PROMPT_ECHO_ON:
700 case PAM_PROMPT_ECHO_OFF:
701 *num = 1;
702 len = plen + mlen + 1;
682 return NULL;
683
684 /* Initialize PAM */
685 if (sshpam_init(authctxt) == -1) {
686 error("PAM: initialization failed");
687 return (NULL);
688 }
689

--- 43 unchanged lines hidden (view full) ---

733 type = buffer_get_char(&buffer);
734 msg = buffer_get_string(&buffer, NULL);
735 mlen = strlen(msg);
736 switch (type) {
737 case PAM_PROMPT_ECHO_ON:
738 case PAM_PROMPT_ECHO_OFF:
739 *num = 1;
740 len = plen + mlen + 1;
703 **prompts = xrealloc(**prompts, len);
741 **prompts = xrealloc(**prompts, 1, len);
704 strlcpy(**prompts + plen, msg, len - plen);
705 plen += mlen;
706 **echo_on = (type == PAM_PROMPT_ECHO_ON);
707 xfree(msg);
708 return (0);
709 case PAM_ERROR_MSG:
710 case PAM_TEXT_INFO:
711 /* accumulate messages */
712 len = plen + mlen + 2;
742 strlcpy(**prompts + plen, msg, len - plen);
743 plen += mlen;
744 **echo_on = (type == PAM_PROMPT_ECHO_ON);
745 xfree(msg);
746 return (0);
747 case PAM_ERROR_MSG:
748 case PAM_TEXT_INFO:
749 /* accumulate messages */
750 len = plen + mlen + 2;
713 **prompts = xrealloc(**prompts, len);
751 **prompts = xrealloc(**prompts, 1, len);
714 strlcpy(**prompts + plen, msg, len - plen);
715 plen += mlen;
716 strlcat(**prompts + plen, "\n", len - plen);
717 plen++;
718 xfree(msg);
719 break;
752 strlcpy(**prompts + plen, msg, len - plen);
753 plen += mlen;
754 strlcat(**prompts + plen, "\n", len - plen);
755 plen++;
756 xfree(msg);
757 break;
758 case PAM_ACCT_EXPIRED:
759 sshpam_account_status = 0;
760 /* FALLTHROUGH */
720 case PAM_AUTH_ERR:
761 case PAM_AUTH_ERR:
721 debug3("PAM: PAM_AUTH_ERR");
762 debug3("PAM: %s", pam_strerror(sshpam_handle, type));
722 if (**prompts != NULL && strlen(**prompts) != 0) {
723 *info = **prompts;
724 **prompts = NULL;
725 *num = 0;
726 **echo_on = 0;
727 ctxt->pam_done = -1;
763 if (**prompts != NULL && strlen(**prompts) != 0) {
764 *info = **prompts;
765 **prompts = NULL;
766 *num = 0;
767 **echo_on = 0;
768 ctxt->pam_done = -1;
769 xfree(msg);
728 return 0;
729 }
730 /* FALLTHROUGH */
731 case PAM_SUCCESS:
732 if (**prompts != NULL) {
733 /* drain any accumulated messages */
734 debug("PAM: %s", **prompts);
735 buffer_append(&loginmsg, **prompts,

--- 190 unchanged lines hidden (view full) ---

926
927 debug3("PAM: %s called with %d messages", __func__, n);
928
929 *resp = NULL;
930
931 if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
932 return (PAM_CONV_ERR);
933
770 return 0;
771 }
772 /* FALLTHROUGH */
773 case PAM_SUCCESS:
774 if (**prompts != NULL) {
775 /* drain any accumulated messages */
776 debug("PAM: %s", **prompts);
777 buffer_append(&loginmsg, **prompts,

--- 190 unchanged lines hidden (view full) ---

968
969 debug3("PAM: %s called with %d messages", __func__, n);
970
971 *resp = NULL;
972
973 if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
974 return (PAM_CONV_ERR);
975
934 if ((reply = malloc(n * sizeof(*reply))) == NULL)
976 if ((reply = calloc(n, sizeof(*reply))) == NULL)
935 return (PAM_CONV_ERR);
977 return (PAM_CONV_ERR);
936 memset(reply, 0, n * sizeof(*reply));
937
938 for (i = 0; i < n; ++i) {
939 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
940 case PAM_PROMPT_ECHO_OFF:
941 reply[i].resp =
942 read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
943 RP_ALLOW_STDIN);
944 reply[i].resp_retcode = PAM_SUCCESS;

--- 236 unchanged lines hidden ---
978
979 for (i = 0; i < n; ++i) {
980 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
981 case PAM_PROMPT_ECHO_OFF:
982 reply[i].resp =
983 read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
984 RP_ALLOW_STDIN);
985 reply[i].resp_retcode = PAM_SUCCESS;

--- 236 unchanged lines hidden ---