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

Collapse All | Expand All

(-)a/auth-pam.c (-243 / +158 lines)
Lines 97-102 Link Here
97
#include "ssh-gss.h"
97
#include "ssh-gss.h"
98
#endif
98
#endif
99
#include "monitor_wrap.h"
99
#include "monitor_wrap.h"
100
#include "ssherr.h"
100
101
101
extern ServerOptions options;
102
extern ServerOptions options;
102
extern Buffer loginmsg;
103
extern Buffer loginmsg;
Lines 109-146 extern u_int utmp_len; Link Here
109
#endif
110
#endif
110
111
111
/*
112
/*
112
 * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
113
 * PAM processing model has been rewritten.
113
 * and generally a bad idea.  Use at own risk and do not expect support if
114
 * Now all the calls to PAM are within the monitor process,
114
 * this breaks.
115
 * pam_get_data/pam_set_data works as designed and there is no need
116
 * for the threads anymore.
115
 */
117
 */
116
#ifdef UNSUPPORTED_POSIX_THREADS_HACK
118
#ifdef UNSUPPORTED_POSIX_THREADS_HACK
117
#include <pthread.h>
119
# error "UNSUPPORTED_POSIX_THREADS_HACK no longer supported"
118
/*
119
 * Avoid namespace clash when *not* using pthreads for systems *with*
120
 * pthreads, which unconditionally define pthread_t via sys/types.h
121
 * (e.g. Linux)
122
 */
123
typedef pthread_t sp_pthread_t;
124
#else
125
typedef pid_t sp_pthread_t;
126
#endif
120
#endif
127
121
128
struct pam_ctxt {
122
struct pam_ctxt {
129
	sp_pthread_t	 pam_thread;
123
	pid_t	 pam_child;
130
	int		 pam_psock;
124
	int	 pam_psock;
131
	int		 pam_csock;
125
	int	 pam_csock;
132
	int		 pam_done;
126
	int	 pam_done;
133
};
127
};
134
128
135
static void sshpam_free_ctx(void *);
129
static void sshpam_free_ctx(void *);
136
static struct pam_ctxt *cleanup_ctxt;
130
static struct pam_ctxt *cleanup_ctxt;
137
131
138
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
132
static int sshpam_child_status = -1;
139
/*
140
 * Simulate threads with processes.
141
 */
142
143
static int sshpam_thread_status = -1;
144
static mysig_t sshpam_oldsig;
133
static mysig_t sshpam_oldsig;
145
134
146
static void
135
static void
Lines 149-226 sshpam_sigchld_handler(int sig) Link Here
149
	signal(SIGCHLD, SIG_DFL);
138
	signal(SIGCHLD, SIG_DFL);
150
	if (cleanup_ctxt == NULL)
139
	if (cleanup_ctxt == NULL)
151
		return;	/* handler called after PAM cleanup, shouldn't happen */
140
		return;	/* handler called after PAM cleanup, shouldn't happen */
152
	if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
141
	if (waitpid(cleanup_ctxt->pam_child, &sshpam_child_status, WNOHANG)
153
	    <= 0) {
142
	    <= 0) {
154
		/* PAM thread has not exitted, privsep slave must have */
143
		/* callback child has not exited, privsep slave must have */
155
		kill(cleanup_ctxt->pam_thread, SIGTERM);
144
		kill(cleanup_ctxt->pam_child, SIGTERM);
156
		if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0)
145
		if (waitpid(cleanup_ctxt->pam_child, &sshpam_child_status, 0)
157
		    <= 0)
146
		    <= 0)
158
			return; /* could not wait */
147
			return; /* could not wait */
159
	}
148
	}
160
	if (WIFSIGNALED(sshpam_thread_status) &&
149
	if (WIFSIGNALED(sshpam_child_status) &&
161
	    WTERMSIG(sshpam_thread_status) == SIGTERM)
150
	    WTERMSIG(sshpam_child_status) == SIGTERM)
162
		return;	/* terminated by pthread_cancel */
151
		return;
163
	if (!WIFEXITED(sshpam_thread_status))
152
	if (!WIFEXITED(sshpam_child_status))
164
		sigdie("PAM: authentication thread exited unexpectedly");
153
		sigdie("PAM: callback child exited unexpectedly");
165
	if (WEXITSTATUS(sshpam_thread_status) != 0)
154
	if (WEXITSTATUS(sshpam_child_status) != 0)
166
		sigdie("PAM: authentication thread exited uncleanly");
155
		sigdie("PAM: callback child exited uncleanly");
167
}
168
169
/* ARGSUSED */
170
static void
171
pthread_exit(void *value)
172
{
173
	_exit(0);
174
}
175
176
/* ARGSUSED */
177
static int
178
pthread_create(sp_pthread_t *thread, const void *attr,
179
    void *(*thread_start)(void *), void *arg)
180
{
181
	pid_t pid;
182
	struct pam_ctxt *ctx = arg;
183
184
	sshpam_thread_status = -1;
185
	switch ((pid = fork())) {
186
	case -1:
187
		error("fork(): %s", strerror(errno));
188
		return (-1);
189
	case 0:
190
		close(ctx->pam_psock);
191
		ctx->pam_psock = -1;
192
		thread_start(arg);
193
		_exit(1);
194
	default:
195
		*thread = pid;
196
		close(ctx->pam_csock);
197
		ctx->pam_csock = -1;
198
		sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
199
		return (0);
200
	}
201
}
202
203
static int
204
pthread_cancel(sp_pthread_t thread)
205
{
206
	signal(SIGCHLD, sshpam_oldsig);
207
	return (kill(thread, SIGTERM));
208
}
209
210
/* ARGSUSED */
211
static int
212
pthread_join(sp_pthread_t thread, void **value)
213
{
214
	int status;
215
216
	if (sshpam_thread_status != -1)
217
		return (sshpam_thread_status);
218
	signal(SIGCHLD, sshpam_oldsig);
219
	waitpid(thread, &status, 0);
220
	return (status);
221
}
156
}
222
#endif
223
224
157
225
static pam_handle_t *sshpam_handle = NULL;
158
static pam_handle_t *sshpam_handle = NULL;
226
static int sshpam_err = 0;
159
static int sshpam_err = 0;
Lines 290-344 sshpam_password_change_required(int reqd) Link Here
290
	}
223
	}
291
}
224
}
292
225
293
/* Import regular and PAM environment from subprocess */
294
static void
295
import_environments(Buffer *b)
296
{
297
	char *env;
298
	u_int i, num_env;
299
	int err;
300
301
	debug3("PAM: %s entering", __func__);
302
303
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
304
	/* Import variables set by do_pam_account */
305
	sshpam_account_status = buffer_get_int(b);
306
	sshpam_password_change_required(buffer_get_int(b));
307
308
	/* Import environment from subprocess */
309
	num_env = buffer_get_int(b);
310
	if (num_env > 1024)
311
		fatal("%s: received %u environment variables, expected <= 1024",
312
		    __func__, num_env);
313
	sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
314
	debug3("PAM: num env strings %d", num_env);
315
	for(i = 0; i < num_env; i++)
316
		sshpam_env[i] = buffer_get_string(b, NULL);
317
318
	sshpam_env[num_env] = NULL;
319
320
	/* Import PAM environment from subprocess */
321
	num_env = buffer_get_int(b);
322
	debug("PAM: num PAM env strings %d", num_env);
323
	for(i = 0; i < num_env; i++) {
324
		env = buffer_get_string(b, NULL);
325
326
#ifdef HAVE_PAM_PUTENV
327
		/* Errors are not fatal here */
328
		if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
329
			error("PAM: pam_putenv: %s",
330
			    pam_strerror(sshpam_handle, sshpam_err));
331
		}
332
#endif
333
	}
334
#endif
335
}
336
337
/*
226
/*
338
 * Conversation function for authentication thread.
227
 * Conversation function for keyboard-interactive authentication.
339
 */
228
 */
340
static int
229
static int
341
sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
230
sshpam_child_conv(int n, sshpam_const struct pam_message **msg,
342
    struct pam_response **resp, void *data)
231
    struct pam_response **resp, void *data)
343
{
232
{
344
	Buffer buffer;
233
	Buffer buffer;
Lines 420-467 sshpam_thread_conv(int n, sshpam_const struct pam_message **msg, Link Here
420
}
309
}
421
310
422
/*
311
/*
423
 * Authentication thread.
312
 * Terminates the call back child.
313
 *
314
 * Sends a message of type PAM_SUCCESS or PAM_AUTH_ERR to the child.
315
 * In response receives a message with remaining PAM prompts.
316
 * When not using privilege separation, receives serialized packet state too.
317
 *
318
 * After that, the child exits.
424
 */
319
 */
425
static void *
320
void
426
sshpam_thread(void *ctxtp)
321
relieve_from_duty(struct pam_ctxt *ctxt)
427
{
322
{
428
	struct pam_ctxt *ctxt = ctxtp;
429
	Buffer buffer;
323
	Buffer buffer;
430
	struct pam_conv sshpam_conv;
324
	struct ssh *ssh = active_state;
431
	int flags = (options.permit_empty_passwd == 0 ?
325
	int r;
432
	    PAM_DISALLOW_NULL_AUTHTOK : 0);
326
	u_char type;
433
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
327
	char *msg;
434
	extern char **environ;
328
	u_int len;
435
	char **env_from_pam;
436
	u_int i;
437
	const char *pam_user;
438
	const char **ptr_pam_user = &pam_user;
439
	char *tz = getenv("TZ");
440
441
	sshpam_err = pam_get_item(sshpam_handle, PAM_USER,
442
	    (sshpam_const void **)ptr_pam_user);
443
	if (sshpam_err != PAM_SUCCESS)
444
		goto auth_fail;
445
329
446
	environ[0] = NULL;
330
	buffer_init(&buffer);
447
	if (tz != NULL)
331
	buffer_put_cstring(&buffer, "OK");
448
		if (setenv("TZ", tz, 1) == -1)
332
	type = (ctxt->pam_done == 1) ? PAM_SUCCESS : PAM_AUTH_ERR;
449
			error("PAM: could not set TZ environment: %s",
333
	if (ssh_msg_send(ctxt->pam_csock, type, &buffer) == -1) {
450
			    strerror(errno));
334
		buffer_free(&buffer);
335
		fatal("%s: cannnot terminate callback child (send)", __func__);
336
	}
451
337
452
	if (sshpam_authctxt != NULL) {
338
	buffer_clear(&buffer);
453
		setproctitle("%s [pam]",
339
	if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) {
454
		    sshpam_authctxt->valid ? pam_user : "unknown");
340
		buffer_free(&buffer);
341
		fatal("%s: cannnot terminate callback child (receive)",
342
		    __func__);
455
	}
343
	}
456
#endif
344
	type = buffer_get_char(&buffer);
345
	msg = buffer_get_cstring(&buffer, &len);
346
	if (len)
347
		buffer_append(&loginmsg, msg, len);
348
	/* if not using privsep child, sync packet state from callback child */	
349
	if (!use_privsep) {
350
		if ((r = ssh_packet_set_state(ssh, &buffer)) != 0)
351
			fatal("%s: set_state failed: %s",
352
			   __func__, ssh_err(r));
353
	}
354
	free(msg);
355
	buffer_free(&buffer);
356
	close(ctxt->pam_csock);
357
	ctxt->pam_csock = -1;
358
}
359
360
int
361
get_pam_done(void *ctxt)
362
{
363
	struct pam_ctxt *pctxt = (struct pam_ctxt *)ctxt;
364
	return (pctxt->pam_done);
365
}
457
366
458
	sshpam_conv.conv = sshpam_thread_conv;
367
/*
368
 * Perform PAM authentication.
369
 *
370
 * PAM APIs (pam_authenticate, pam_acct_mgmt, ...) block and call the
371
 * provided callback conversation function (sshpam_conv). The conversation
372
 * function sends messages to the callback child (pam_ctxt.pam_child), which
373
 * communicates with the client directly, or indirectly through privsep child.
374
 */
375
void
376
do_pam_auth(struct pam_ctxt *ctxt)
377
{
378
	struct pam_conv sshpam_conv;
379
	int flags = (options.permit_empty_passwd == 0 ?
380
	    PAM_DISALLOW_NULL_AUTHTOK : 0);
381
382
	sshpam_conv.conv = sshpam_child_conv;
459
	sshpam_conv.appdata_ptr = ctxt;
383
	sshpam_conv.appdata_ptr = ctxt;
460
384
385
	ctxt->pam_done = -1;
386
461
	if (sshpam_authctxt == NULL)
387
	if (sshpam_authctxt == NULL)
462
		fatal("%s: PAM authctxt not initialized", __func__);
388
		fatal("%s: PAM authctxt not initialized", __func__);
463
389
464
	buffer_init(&buffer);
465
	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
390
	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
466
	    (const void *)&sshpam_conv);
391
	    (const void *)&sshpam_conv);
467
	if (sshpam_err != PAM_SUCCESS)
392
	if (sshpam_err != PAM_SUCCESS)
Lines 484-543 sshpam_thread(void *ctxtp) Link Here
484
		}
409
		}
485
	}
410
	}
486
411
487
	buffer_put_cstring(&buffer, "OK");
412
	ctxt->pam_done = 1;
488
489
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
490
	/* Export variables set by do_pam_account */
491
	buffer_put_int(&buffer, sshpam_account_status);
492
	buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
493
494
	/* Export any environment strings set in child */
495
	for(i = 0; environ[i] != NULL; i++)
496
		; /* Count */
497
	buffer_put_int(&buffer, i);
498
	for(i = 0; environ[i] != NULL; i++)
499
		buffer_put_cstring(&buffer, environ[i]);
500
501
	/* Export any environment strings set by PAM in child */
502
	env_from_pam = pam_getenvlist(sshpam_handle);
503
	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
504
		; /* Count */
505
	buffer_put_int(&buffer, i);
506
	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
507
		buffer_put_cstring(&buffer, env_from_pam[i]);
508
#endif /* UNSUPPORTED_POSIX_THREADS_HACK */
509
510
	/* XXX - can't do much about an error here */
511
	ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
512
	buffer_free(&buffer);
513
	pthread_exit(NULL);
514
413
515
 auth_fail:
414
 auth_fail:
516
	buffer_put_cstring(&buffer,
415
	if (sshpam_err != PAM_SUCCESS)
517
	    pam_strerror(sshpam_handle, sshpam_err));
416
		error("PAM: %s for %s%.100s from %.100s",
518
	/* XXX - can't do much about an error here */
417
		    pam_strerror(sshpam_handle, sshpam_err),
519
	if (sshpam_err == PAM_ACCT_EXPIRED)
418
		    sshpam_authctxt->valid ? "" : "illegal user ",
520
		ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer);
419
		    sshpam_authctxt->user,
521
	else
420
		    get_remote_name_or_ip(utmp_len, options.use_dns));
522
		ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
421
	relieve_from_duty(ctxt);
523
	buffer_free(&buffer);
524
	pthread_exit(NULL);
525
526
	return (NULL); /* Avoid warning for non-pthread case */
527
}
422
}
528
423
529
void
424
void
530
sshpam_thread_cleanup(void)
425
sshpam_child_cleanup(void)
531
{
426
{
532
	struct pam_ctxt *ctxt = cleanup_ctxt;
427
	struct pam_ctxt *ctxt = cleanup_ctxt;
533
428
534
	debug3("PAM: %s entering", __func__);
429
	debug3("PAM: %s entering", __func__);
535
	if (ctxt != NULL && ctxt->pam_thread != 0) {
430
	if (ctxt != NULL && ctxt->pam_child != 0) {
536
		pthread_cancel(ctxt->pam_thread);
431
		signal(SIGCHLD, sshpam_oldsig);
537
		pthread_join(ctxt->pam_thread, NULL);
432
		/* callback child should have had exited by now */
538
		close(ctxt->pam_psock);
433
		kill(ctxt->pam_child, SIGTERM);
539
		close(ctxt->pam_csock);
434
		if (ctxt->pam_psock != -1)
540
		memset(ctxt, 0, sizeof(*ctxt));
435
			close(ctxt->pam_psock);
436
		if (ctxt->pam_csock != -1)
437
			close(ctxt->pam_csock);
438
		if (sshpam_child_status == -1)
439
			waitpid(ctxt->pam_child, &sshpam_child_status, 0);
541
		cleanup_ctxt = NULL;
440
		cleanup_ctxt = NULL;
542
	}
441
	}
543
}
442
}
Lines 673-678 sshpam_init_ctx(Authctxt *authctxt) Link Here
673
{
572
{
674
	struct pam_ctxt *ctxt;
573
	struct pam_ctxt *ctxt;
675
	int socks[2];
574
	int socks[2];
575
	pid_t pid;
676
576
677
	debug3("PAM: %s entering", __func__);
577
	debug3("PAM: %s entering", __func__);
678
	/*
578
	/*
Lines 690-696 sshpam_init_ctx(Authctxt *authctxt) Link Here
690
590
691
	ctxt = xcalloc(1, sizeof *ctxt);
591
	ctxt = xcalloc(1, sizeof *ctxt);
692
592
693
	/* Start the authentication thread */
593
	/* Fork the callback child and start PAM authentication */
694
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
594
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
695
		error("PAM: failed create sockets: %s", strerror(errno));
595
		error("PAM: failed create sockets: %s", strerror(errno));
696
		free(ctxt);
596
		free(ctxt);
Lines 698-712 sshpam_init_ctx(Authctxt *authctxt) Link Here
698
	}
598
	}
699
	ctxt->pam_psock = socks[0];
599
	ctxt->pam_psock = socks[0];
700
	ctxt->pam_csock = socks[1];
600
	ctxt->pam_csock = socks[1];
701
	if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {
601
702
		error("PAM: failed to start authentication thread: %s",
602
	sshpam_child_status = -1;
703
		    strerror(errno));
603
	switch ((pid = fork())) {
604
	case -1:
605
		error("fork(): %s", strerror(errno));
704
		close(socks[0]);
606
		close(socks[0]);
705
		close(socks[1]);
607
		close(socks[1]);
706
		free(ctxt);
608
		free(ctxt);
707
		return (NULL);
609
		return (NULL);
610
	case 0:
611
		/* child processes query & respond for kbdint */
612
		close(ctxt->pam_csock);
613
		ctxt->pam_csock = -1;
614
		break;
615
	default:
616
		/* parent does PAM */
617
		ctxt->pam_child = pid;
618
		close(ctxt->pam_psock);
619
		ctxt->pam_psock = -1;
620
		sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
621
		cleanup_ctxt = ctxt;
622
		do_pam_auth(ctxt);
708
	}
623
	}
709
	cleanup_ctxt = ctxt;
710
	return (ctxt);
624
	return (ctxt);
711
}
625
}
712
626
Lines 720-727 sshpam_query(void *ctx, char **name, char **info, Link Here
720
	u_char type;
634
	u_char type;
721
	char *msg;
635
	char *msg;
722
	size_t len, mlen;
636
	size_t len, mlen;
637
	struct ssh *ssh;
638
	int r;
723
639
724
	debug3("PAM: %s entering", __func__);
640
	debug3("PAM: %s entering", __func__);
641
725
	buffer_init(&buffer);
642
	buffer_init(&buffer);
726
	*name = xstrdup("");
643
	*name = xstrdup("");
727
	*info = xstrdup("");
644
	*info = xstrdup("");
Lines 729-734 sshpam_query(void *ctx, char **name, char **info, Link Here
729
	**prompts = NULL;
646
	**prompts = NULL;
730
	plen = 0;
647
	plen = 0;
731
	*echo_on = xmalloc(sizeof(u_int));
648
	*echo_on = xmalloc(sizeof(u_int));
649
650
	/* in case PAM was already done in callback child */
651
	switch (ctxt->pam_done) {
652
	case 1:
653
		return (0);
654
	case 0:
655
		break;
656
	default:
657
		return (-1);
658
	}
659
732
	while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
660
	while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
733
		type = buffer_get_char(&buffer);
661
		type = buffer_get_char(&buffer);
734
		msg = buffer_get_string(&buffer, NULL);
662
		msg = buffer_get_string(&buffer, NULL);
Lines 760-774 sshpam_query(void *ctx, char **name, char **info, Link Here
760
			/* FALLTHROUGH */
688
			/* FALLTHROUGH */
761
		case PAM_AUTH_ERR:
689
		case PAM_AUTH_ERR:
762
			debug3("PAM: %s", pam_strerror(sshpam_handle, type));
690
			debug3("PAM: %s", pam_strerror(sshpam_handle, type));
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
				free(msg);
770
				return 0;
771
			}
772
			/* FALLTHROUGH */
691
			/* FALLTHROUGH */
773
		case PAM_SUCCESS:
692
		case PAM_SUCCESS:
774
			if (**prompts != NULL) {
693
			if (**prompts != NULL) {
Lines 779-803 sshpam_query(void *ctx, char **name, char **info, Link Here
779
				free(**prompts);
698
				free(**prompts);
780
				**prompts = NULL;
699
				**prompts = NULL;
781
			}
700
			}
782
			if (type == PAM_SUCCESS) {
701
			/* send accumulated messages to parent */
783
				if (!sshpam_authctxt->valid ||
702
			buffer_clear(&buffer);
784
				    (sshpam_authctxt->pw->pw_uid == 0 &&
703
			buffer_put_cstring(&buffer, buffer_ptr(&loginmsg));
785
				    options.permit_root_login != PERMIT_YES))
704
			if (!use_privsep) {
786
					fatal("Internal error: PAM auth "
705
				/* sync packet state with parrent */
787
					    "succeeded when it should have "
706
				ssh = active_state;
788
					    "failed");
707
				r = ssh_packet_get_state(ssh, &buffer);
789
				import_environments(&buffer);
708
				if (r != 0)
790
				*num = 0;
709
					fatal("%s: get_state failed: %s",
791
				**echo_on = 0;
710
					   __func__, ssh_err(r));
792
				ctxt->pam_done = 1;
793
				free(msg);
794
				return (0);
795
			}
711
			}
796
			error("PAM: %s for %s%.100s from %.100s", msg,
712
			ssh_msg_send(ctxt->pam_psock, type, &buffer);
797
			    sshpam_authctxt->valid ? "" : "illegal user ",
713
			/* callback child ends here */
798
			    sshpam_authctxt->user,
714
			close(ctxt->pam_psock);
799
			    get_remote_name_or_ip(utmp_len, options.use_dns));
715
			exit(0);
800
			/* FALLTHROUGH */
801
		default:
716
		default:
802
			*num = 0;
717
			*num = 0;
803
			**echo_on = 0;
718
			**echo_on = 0;
Lines 851-857 sshpam_free_ctx(void *ctxtp) Link Here
851
	struct pam_ctxt *ctxt = ctxtp;
766
	struct pam_ctxt *ctxt = ctxtp;
852
767
853
	debug3("PAM: %s entering", __func__);
768
	debug3("PAM: %s entering", __func__);
854
	sshpam_thread_cleanup();
769
	sshpam_child_cleanup();
855
	free(ctxt);
770
	free(ctxt);
856
	/*
771
	/*
857
	 * We don't call sshpam_cleanup() here because we may need the PAM
772
	 * We don't call sshpam_cleanup() here because we may need the PAM
(-)a/auth-pam.h (-1 / +2 lines)
Lines 42-50 int do_pam_putenv(char *, char *); Link Here
42
char ** fetch_pam_environment(void);
42
char ** fetch_pam_environment(void);
43
char ** fetch_pam_child_environment(void);
43
char ** fetch_pam_child_environment(void);
44
void free_pam_environment(char **);
44
void free_pam_environment(char **);
45
void sshpam_thread_cleanup(void);
45
void sshpam_child_cleanup(void);
46
void sshpam_cleanup(void);
46
void sshpam_cleanup(void);
47
int sshpam_auth_passwd(Authctxt *, const char *);
47
int sshpam_auth_passwd(Authctxt *, const char *);
48
int is_pam_session_open(void);
48
int is_pam_session_open(void);
49
int get_pam_done(void *);
49
50
50
#endif /* USE_PAM */
51
#endif /* USE_PAM */
(-)a/monitor.c (-1 / +28 lines)
Lines 1086-1097 mm_answer_pam_init_ctx(int sock, Buffer *m) Link Here
1086
	sshpam_ctxt = (sshpam_device.init_ctx)(authctxt);
1086
	sshpam_ctxt = (sshpam_device.init_ctx)(authctxt);
1087
	sshpam_authok = NULL;
1087
	sshpam_authok = NULL;
1088
	buffer_clear(m);
1088
	buffer_clear(m);
1089
	int pam_done = 0;
1089
	if (sshpam_ctxt != NULL) {
1090
	if (sshpam_ctxt != NULL) {
1090
		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
1091
		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
1091
		buffer_put_int(m, 1);
1092
		buffer_put_int(m, 1);
1092
	} else {
1093
	} else {
1093
		buffer_put_int(m, 0);
1094
		buffer_put_int(m, 0);
1094
	}
1095
	}
1096
1097
	/* pam conversation successfully finished in child process */
1098
	if (sshpam_ctxt != NULL && 
1099
	    (pam_done = get_pam_done(sshpam_ctxt)) != 0) {
1100
		auth_method = "keyboard-interactive";
1101
		auth_submethod = "pam";
1102
		/* 
1103
		 * ANS_PAM_INIT_CTX already sent by callback child.
1104
		 * Privsep child now expects ANS_PAM_QUERY.
1105
		 */
1106
		buffer_clear(m);
1107
		buffer_put_int(m, 0);		/* ret */
1108
		buffer_put_cstring(m, "");	/* name */
1109
		if (pam_done == 1) {		/* info */
1110
			buffer_put_cstring(m, "");
1111
		} else {
1112
			buffer_put_string(m, buffer_ptr(&loginmsg),
1113
			    buffer_len(&loginmsg));
1114
			buffer_clear(&loginmsg);
1115
		}
1116
		buffer_put_int(m, 0);		/* num */
1117
		mm_request_send(sock, MONITOR_ANS_PAM_QUERY, m);
1118
		return (0);
1119
	}
1120
1095
	mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m);
1121
	mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m);
1096
	return (0);
1122
	return (0);
1097
}
1123
}
Lines 1845-1851 monitor_apply_keystate(struct monitor *pmonitor) Link Here
1845
	int r;
1871
	int r;
1846
1872
1847
	debug3("%s: packet_set_state", __func__);
1873
	debug3("%s: packet_set_state", __func__);
1848
	if ((r = ssh_packet_set_state(ssh, child_state)) != 0)
1874
	if ((r = ssh_packet_set_state(ssh, child_state)) != 0 ||
1875
	    (r = ssh_packet_set_postauth(ssh)) != 0)
1849
                fatal("%s: packet_set_state: %s", __func__, ssh_err(r));
1876
                fatal("%s: packet_set_state: %s", __func__, ssh_err(r));
1850
	sshbuf_free(child_state);
1877
	sshbuf_free(child_state);
1851
	child_state = NULL;
1878
	child_state = NULL;
(-)a/packet.c (-3 / +2 lines)
Lines 2367-2373 ssh_packet_restore_state(struct ssh *ssh, Link Here
2367
}
2367
}
2368
2368
2369
/* Reset after_authentication and reset compression in post-auth privsep */
2369
/* Reset after_authentication and reset compression in post-auth privsep */
2370
static int
2370
int
2371
ssh_packet_set_postauth(struct ssh *ssh)
2371
ssh_packet_set_postauth(struct ssh *ssh)
2372
{
2372
{
2373
	struct sshcomp *comp;
2373
	struct sshcomp *comp;
Lines 2699-2706 ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m) Link Here
2699
	cipher_set_keycontext(&state->send_context, keyout);
2699
	cipher_set_keycontext(&state->send_context, keyout);
2700
	cipher_set_keycontext(&state->receive_context, keyin);
2700
	cipher_set_keycontext(&state->receive_context, keyin);
2701
2701
2702
	if ((r = ssh_packet_set_compress_state(ssh, m)) != 0 ||
2702
	if ((r = ssh_packet_set_compress_state(ssh, m)) != 0)
2703
	    (r = ssh_packet_set_postauth(ssh)) != 0)
2704
		return r;
2703
		return r;
2705
2704
2706
	sshbuf_reset(state->input);
2705
	sshbuf_reset(state->input);
(-)a/packet.h (+1 lines)
Lines 141-146 u_int ssh_packet_get_maxsize(struct ssh *); Link Here
141
141
142
int	 ssh_packet_get_state(struct ssh *, struct sshbuf *);
142
int	 ssh_packet_get_state(struct ssh *, struct sshbuf *);
143
int	 ssh_packet_set_state(struct ssh *, struct sshbuf *);
143
int	 ssh_packet_set_state(struct ssh *, struct sshbuf *);
144
int	 ssh_packet_set_postauth(struct ssh *ssh);
144
145
145
const char *ssh_remote_ipaddr(struct ssh *);
146
const char *ssh_remote_ipaddr(struct ssh *);
146
int	 ssh_remote_port(struct ssh *);
147
int	 ssh_remote_port(struct ssh *);
(-)a/servconf.c (+12 lines)
Lines 389-394 fill_default_server_options(ServerOptions *options) Link Here
389
		options->compression = 0;
389
		options->compression = 0;
390
	}
390
	}
391
#endif
391
#endif
392
#ifdef USE_PAM
393
	if (!use_privsep && options->compression == COMP_ZLIB && 
394
	    options->use_pam && 
395
	    (options->kbd_interactive_authentication || 
396
	     options->challenge_response_authentication)) {
397
		error("Compression algorithm 'zlib' is not supported for "
398
		    "PAM authentication when privilege separation is off");
399
		error("Limmiting compression algorithms to "
400
		    "'none,zlib@openssh.com'");
401
		options->compression = COMP_DELAYED;
402
	}
403
#endif
392
404
393
}
405
}
394
406
(-)a/session.c (-2 / +1 lines)
Lines 2738-2744 do_cleanup(Authctxt *authctxt) Link Here
2738
#ifdef USE_PAM
2738
#ifdef USE_PAM
2739
	if (options.use_pam) {
2739
	if (options.use_pam) {
2740
		sshpam_cleanup();
2740
		sshpam_cleanup();
2741
		sshpam_thread_cleanup();
2741
		sshpam_child_cleanup();
2742
	}
2742
	}
2743
#endif
2743
#endif
2744
2744
2745
- 

Return to bug 2548