View | Details | Raw Unified | Return to bug 423 | Differences between
and this patch

Collapse All | Expand All

(-)auth-pam.c (-20 / +24 lines)
Lines 33-49 Link Here
33
#include "servconf.h"
33
#include "servconf.h"
34
#include "canohost.h"
34
#include "canohost.h"
35
#include "readpass.h"
35
#include "readpass.h"
36
#include "channels.h"
37
#include "misc.h"
36
38
37
extern char *__progname;
39
extern char *__progname;
38
40
39
extern int use_privsep;
41
extern int use_privsep;
42
extern ServerOptions options;
40
43
41
RCSID("$Id: auth-pam.c,v 1.54 2002/07/28 20:24:08 stevesk Exp $");
44
RCSID("$Id: auth-pam.c,v 1.54 2002/07/28 20:24:08 stevesk Exp $");
42
45
43
#define NEW_AUTHTOK_MSG \
46
#define NEW_AUTHTOK_MSG \
44
	"Warning: Your password has expired, please change it now."
47
	"Warning: Your password has expired, please change it now."
45
#define NEW_AUTHTOK_MSG_PRIVSEP \
46
	"Your password has expired, the session cannot proceed."
47
48
48
static int do_pam_conversation(int num_msg, const struct pam_message **msg,
49
static int do_pam_conversation(int num_msg, const struct pam_message **msg,
49
	struct pam_response **resp, void *appdata_ptr);
50
	struct pam_response **resp, void *appdata_ptr);
Lines 204-210 Link Here
204
/* Attempt password authentation using PAM */
205
/* Attempt password authentation using PAM */
205
int auth_pam_password(Authctxt *authctxt, const char *password)
206
int auth_pam_password(Authctxt *authctxt, const char *password)
206
{
207
{
207
	extern ServerOptions options;
208
	int pam_retval;
208
	int pam_retval;
209
	struct passwd *pw = authctxt->pw;
209
	struct passwd *pw = authctxt->pw;
210
210
Lines 256-273 Link Here
256
		case PAM_SUCCESS:
256
		case PAM_SUCCESS:
257
			/* This is what we want */
257
			/* This is what we want */
258
			break;
258
			break;
259
#if 0
260
		case PAM_NEW_AUTHTOK_REQD:
259
		case PAM_NEW_AUTHTOK_REQD:
261
			message_cat(&__pam_msg, use_privsep ?
260
			message_cat(&__pam_msg, NEW_AUTHTOK_MSG);
262
			    NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG);
263
			/* flag that password change is necessary */
261
			/* flag that password change is necessary */
264
			password_change_required = 1;
262
			password_change_required = 1;
265
			/* disallow other functionality for now */
263
			/* disallow other functionality for now */
266
			no_port_forwarding_flag |= 2;
264
			no_port_forwarding_flag |= 2;
267
			no_agent_forwarding_flag |= 2;
265
			no_agent_forwarding_flag |= 2;
268
			no_x11_forwarding_flag |= 2;
266
			no_x11_forwarding_flag |= 2;
267
			/* set signal handler to restore flags */
268
			mysignal(SIGUSR1, password_change_successful_handler);
269
			break;
269
			break;
270
#endif
271
		default:
270
		default:
272
			log("PAM rejected by account configuration[%d]: "
271
			log("PAM rejected by account configuration[%d]: "
273
			    "%.200s", pam_retval, PAM_STRERROR(__pamh, 
272
			    "%.200s", pam_retval, PAM_STRERROR(__pamh, 
Lines 344-369 Link Here
344
	do_pam_set_conv(&conv);
343
	do_pam_set_conv(&conv);
345
344
346
	if (password_change_required) {
345
	if (password_change_required) {
347
		if (use_privsep)
348
			fatal("Password changing is currently unsupported"
349
			    " with privilege separation");
350
		pamstate = OTHER;
346
		pamstate = OTHER;
351
		pam_retval = pam_chauthtok(__pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
347
		pam_retval = pam_chauthtok(__pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
352
		if (pam_retval != PAM_SUCCESS)
348
		if (pam_retval != PAM_SUCCESS)
353
			fatal("PAM pam_chauthtok failed[%d]: %.200s",
349
			fatal("PAM pam_chauthtok failed[%d]: %.200s",
354
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
350
			    pam_retval, PAM_STRERROR(__pamh, pam_retval));
355
#if 0
351
		password_change_required = 0;
356
		/* XXX: This would need to be done in the parent process,
357
		 * but there's currently no way to pass such request. */
358
		no_port_forwarding_flag &= ~2;
359
		no_agent_forwarding_flag &= ~2;
360
		no_x11_forwarding_flag &= ~2;
361
		if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
362
			channel_permit_all_opens();
363
#endif
364
	}
352
	}
365
}
353
}
366
354
355
/*
356
 * Because do_pam_chauthtok is called after forking to exec the user's
357
 * shell, restoring the port forwarding flags is done by sending a
358
 * USR1 signal after the password is changed successfully.
359
 */
360
void password_change_successful_handler(int sig)
361
{
362
	debug("%s: restoring port forwarding flags", __func__);
363
	mysignal(SIGUSR1, SIG_DFL);	/* unset handler */
364
	password_change_required = 0;
365
	no_port_forwarding_flag &= ~2;
366
	no_agent_forwarding_flag &= ~2;
367
	no_x11_forwarding_flag &= ~2;
368
	if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
369
		channel_permit_all_opens();
370
}
371
367
/* Cleanly shutdown PAM */
372
/* Cleanly shutdown PAM */
368
void finish_pam(void)
373
void finish_pam(void)
369
{
374
{
Lines 375-381 Link Here
375
void start_pam(const char *user)
380
void start_pam(const char *user)
376
{
381
{
377
	int pam_retval;
382
	int pam_retval;
378
	extern ServerOptions options;
379
	extern u_int utmp_len;
383
	extern u_int utmp_len;
380
	const char *rhost;
384
	const char *rhost;
381
385
(-)auth-pam.h (+1 lines)
Lines 43-48 Link Here
43
void print_pam_messages(void);
43
void print_pam_messages(void);
44
int is_pam_password_change_required(void);
44
int is_pam_password_change_required(void);
45
void do_pam_chauthtok(void);
45
void do_pam_chauthtok(void);
46
void password_change_successful_handler(int);
46
void do_pam_set_conv(struct pam_conv *);
47
void do_pam_set_conv(struct pam_conv *);
47
void message_cat(char **p, const char *a);
48
void message_cat(char **p, const char *a);
48
49
(-)monitor.c (+58 lines)
Lines 118-123 Link Here
118
118
119
#ifdef USE_PAM
119
#ifdef USE_PAM
120
int mm_answer_pam_start(int, Buffer *);
120
int mm_answer_pam_start(int, Buffer *);
121
int mm_answer_pam_chauthtok(int, Buffer *);
121
#endif
122
#endif
122
123
123
#ifdef KRB4
124
#ifdef KRB4
Lines 183-188 Link Here
183
    {MONITOR_REQ_PTY, 0, mm_answer_pty},
184
    {MONITOR_REQ_PTY, 0, mm_answer_pty},
184
    {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
185
    {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
185
    {MONITOR_REQ_TERM, 0, mm_answer_term},
186
    {MONITOR_REQ_TERM, 0, mm_answer_term},
187
#ifdef USE_PAM
188
    {MONITOR_REQ_PAM_CHAUTHTOK, 0, mm_answer_pam_chauthtok},
189
#endif
186
    {0, 0, NULL}
190
    {0, 0, NULL}
187
};
191
};
188
192
Lines 219-224 Link Here
219
    {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
223
    {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
220
    {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
224
    {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
221
    {MONITOR_REQ_TERM, 0, mm_answer_term},
225
    {MONITOR_REQ_TERM, 0, mm_answer_term},
226
#ifdef USE_PAM
227
    {MONITOR_REQ_PAM_CHAUTHTOK, 0, mm_answer_pam_chauthtok},
228
#endif
222
    {0, 0, NULL}
229
    {0, 0, NULL}
223
};
230
};
224
231
Lines 328-333 Link Here
328
	if (!no_pty_flag) {
335
	if (!no_pty_flag) {
329
		monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
336
		monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
330
		monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
337
		monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
338
		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_CHAUTHTOK, 1);
331
	}
339
	}
332
340
333
	for (;;)
341
	for (;;)
Lines 746-751 Link Here
746
	xfree(user);
754
	xfree(user);
747
755
748
	return (0);
756
	return (0);
757
}
758
759
int
760
mm_answer_pam_chauthtok(int socket, Buffer *m)
761
{
762
	pid_t pid;
763
	int ttyfd, status;
764
	mysig_t old_signal;
765
766
	old_signal = mysignal(SIGCHLD, SIG_DFL);
767
768
	ttyfd = mm_receive_fd(socket);
769
	debug3("%s: ttyfd %d, ttyname %s", __func__, ttyfd, ttyname(ttyfd));
770
771
	if ((pid = fork()) == 0) {
772
		fatal_remove_all_cleanups();
773
774
		/* set up stdin, stdout and stderr */
775
		if (dup2(ttyfd, 0) < 0)
776
			error("dup2 stdin: %s", strerror(errno));
777
		if (dup2(ttyfd, 1) < 0)
778
			error("dup2 stdout: %s", strerror(errno));
779
		if (dup2(ttyfd, 2) < 0)
780
			error("dup2 stderr: %s", strerror(errno));
781
782
		/* call PAM chauthtok and return status to parent */
783
		do_pam_chauthtok();
784
785
		if(is_pam_password_change_required())
786
			exit(1); 	/* failed */
787
		else
788
			exit(0);	/* success */
789
	}
790
791
	close(ttyfd);
792
793
	if (waitpid(pid, &status, 0) == -1)
794
		fatal("Couldn't wait for child: %s", strerror(errno));
795
	debug("chauthtok child returned %d", status);
796
	 
797
	if (WIFEXITED(status) && (WEXITSTATUS(status) == 0))
798
		debug("password changed sucessfully");
799
	else
800
		fatal("do_pam_chauthtok() failed, child returned %d", status);
801
802
	mysignal(SIGCHLD, old_signal);
803
804
	mm_request_send(socket, MONITOR_ANS_PAM_CHAUTHTOK, m);
805
806
	return 1;
749
}
807
}
750
#endif
808
#endif
751
809
(-)monitor.h (+1 lines)
Lines 52-57 Link Here
52
	MONITOR_REQ_KRB4, MONITOR_ANS_KRB4,
52
	MONITOR_REQ_KRB4, MONITOR_ANS_KRB4,
53
 	MONITOR_REQ_KRB5, MONITOR_ANS_KRB5,
53
 	MONITOR_REQ_KRB5, MONITOR_ANS_KRB5,
54
	MONITOR_REQ_PAM_START,
54
	MONITOR_REQ_PAM_START,
55
	MONITOR_REQ_PAM_CHAUTHTOK, MONITOR_ANS_PAM_CHAUTHTOK,
55
	MONITOR_REQ_TERM
56
	MONITOR_REQ_TERM
56
};
57
};
57
58
(-)monitor_wrap.c (+21 lines)
Lines 663-668 Link Here
663
663
664
	buffer_free(&m);
664
	buffer_free(&m);
665
}
665
}
666
667
/*
668
 * Privsep chauthtok works by passing a descriptor to the session's
669
 * stdin/stdout to the monitor, which then sets up a child with this
670
 * descriptor as stdin, stdout then calls do_pam_chauthtok
671
 */
672
673
void
674
mm_do_pam_chauthtok(void)
675
{
676
	Buffer m;
677
678
	debug3("%s entering", __func__);
679
	
680
	buffer_init(&m);
681
	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_CHAUTHTOK, &m);
682
	mm_send_fd(pmonitor->m_recvfd, STDIN_FILENO);
683
	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_CHAUTHTOK, &m);
684
685
	buffer_free(&m);
686
}
666
#endif /* USE_PAM */
687
#endif /* USE_PAM */
667
688
668
/* Request process termination */
689
/* Request process termination */
(-)monitor_wrap.h (+1 lines)
Lines 57-62 Link Here
57
57
58
#ifdef USE_PAM
58
#ifdef USE_PAM
59
void mm_start_pam(char *);
59
void mm_start_pam(char *);
60
void mm_do_pam_chauthtok(void);
60
#endif
61
#endif
61
62
62
void mm_terminate(void);
63
void mm_terminate(void);
(-)session.c (-1 / +4 lines)
Lines 753-759 Link Here
753
	 */
753
	 */
754
	if (is_pam_password_change_required()) {
754
	if (is_pam_password_change_required()) {
755
		print_pam_messages();
755
		print_pam_messages();
756
		do_pam_chauthtok();
756
		PRIVSEP(do_pam_chauthtok());
757
		/* change successful, tell parent to restore port
758
		 * forwarding flags */
759
		kill(getppid(), SIGUSR1);
757
	}
760
	}
758
#endif
761
#endif
759
762
(-)openbsd-compat/readpassphrase.c (+9 lines)
Lines 85-90 Link Here
85
		output = STDERR_FILENO;
85
		output = STDERR_FILENO;
86
	}
86
	}
87
87
88
        /*
89
	 * Odd case where stdin is a tty but /dev/tty is not
90
	 * available. Used for passed file descriptor during privsep.
91
	 */
92
       if (isatty(STDIN_FILENO)) {
93
               input = dup(STDIN_FILENO);
94
               output = dup(STDERR_FILENO);
95
       }
96
88
	/*
97
	/*
89
	 * Catch signals that would otherwise cause the user to end
98
	 * Catch signals that would otherwise cause the user to end
90
	 * up with echo turned off in the shell.  Don't worry about
99
	 * up with echo turned off in the shell.  Don't worry about

Return to bug 423