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

Collapse All | Expand All

(-)a/auth-pam.c (-251 / +159 lines)
Lines 103-108 extern char *__progname; Link Here
103
#include "ssh-gss.h"
103
#include "ssh-gss.h"
104
#endif
104
#endif
105
#include "monitor_wrap.h"
105
#include "monitor_wrap.h"
106
#include "ssherr.h"
106
107
107
extern ServerOptions options;
108
extern ServerOptions options;
108
extern Buffer loginmsg;
109
extern Buffer loginmsg;
Lines 115-152 extern u_int utmp_len; Link Here
115
#endif
116
#endif
116
117
117
/*
118
/*
118
 * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
119
 * PAM processing model has been rewritten.
119
 * and generally a bad idea.  Use at own risk and do not expect support if
120
 * Now all the calls to PAM are within the monitor process,
120
 * this breaks.
121
 * pam_get_data/pam_set_data works as designed and there is no need
122
 * for the threads anymore.
121
 */
123
 */
122
#ifdef UNSUPPORTED_POSIX_THREADS_HACK
124
#ifdef UNSUPPORTED_POSIX_THREADS_HACK
123
#include <pthread.h>
125
# error "UNSUPPORTED_POSIX_THREADS_HACK no longer supported"
124
/*
125
 * Avoid namespace clash when *not* using pthreads for systems *with*
126
 * pthreads, which unconditionally define pthread_t via sys/types.h
127
 * (e.g. Linux)
128
 */
129
typedef pthread_t sp_pthread_t;
130
#else
131
typedef pid_t sp_pthread_t;
132
#endif
126
#endif
133
127
134
struct pam_ctxt {
128
struct pam_ctxt {
135
	sp_pthread_t	 pam_thread;
129
	pid_t	 pam_child;
136
	int		 pam_psock;
130
	int	 pam_psock;
137
	int		 pam_csock;
131
	int	 pam_csock;
138
	int		 pam_done;
132
	int	 pam_done;
139
};
133
};
140
134
141
static void sshpam_free_ctx(void *);
135
static void sshpam_free_ctx(void *);
142
static struct pam_ctxt *cleanup_ctxt;
136
static struct pam_ctxt *cleanup_ctxt;
143
137
144
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
138
static int sshpam_child_status = -1;
145
/*
146
 * Simulate threads with processes.
147
 */
148
149
static int sshpam_thread_status = -1;
150
static mysig_t sshpam_oldsig;
139
static mysig_t sshpam_oldsig;
151
140
152
static void
141
static void
Lines 155-239 sshpam_sigchld_handler(int sig) Link Here
155
	signal(SIGCHLD, SIG_DFL);
144
	signal(SIGCHLD, SIG_DFL);
156
	if (cleanup_ctxt == NULL)
145
	if (cleanup_ctxt == NULL)
157
		return;	/* handler called after PAM cleanup, shouldn't happen */
146
		return;	/* handler called after PAM cleanup, shouldn't happen */
158
	if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
147
	if (waitpid(cleanup_ctxt->pam_child, &sshpam_child_status, WNOHANG)
159
	    <= 0) {
148
	    <= 0) {
160
		/* PAM thread has not exitted, privsep slave must have */
149
		/* callback child has not exited, privsep slave must have */
161
		kill(cleanup_ctxt->pam_thread, SIGTERM);
150
		kill(cleanup_ctxt->pam_child, SIGTERM);
162
		while (waitpid(cleanup_ctxt->pam_thread,
151
		while (waitpid(cleanup_ctxt->pam_child,
163
		    &sshpam_thread_status, 0) == -1) {
152
		    &sshpam_child_status, 0) == -1) {
164
			if (errno == EINTR)
153
			if (errno == EINTR)
165
				continue;
154
				continue;
166
			return;
155
			return;
167
		}
156
		}
168
	}
157
	}
169
	if (WIFSIGNALED(sshpam_thread_status) &&
158
	if (WIFSIGNALED(sshpam_child_status) &&
170
	    WTERMSIG(sshpam_thread_status) == SIGTERM)
159
	    WTERMSIG(sshpam_child_status) == SIGTERM)
171
		return;	/* terminated by pthread_cancel */
160
		return;
172
	if (!WIFEXITED(sshpam_thread_status))
161
	if (!WIFEXITED(sshpam_child_status))
173
		sigdie("PAM: authentication thread exited unexpectedly");
162
		sigdie("PAM: callback child exited unexpectedly");
174
	if (WEXITSTATUS(sshpam_thread_status) != 0)
163
	if (WEXITSTATUS(sshpam_child_status) != 0)
175
		sigdie("PAM: authentication thread exited uncleanly");
164
		sigdie("PAM: callback child exited uncleanly");
176
}
177
178
/* ARGSUSED */
179
static void
180
pthread_exit(void *value)
181
{
182
	_exit(0);
183
}
184
185
/* ARGSUSED */
186
static int
187
pthread_create(sp_pthread_t *thread, const void *attr,
188
    void *(*thread_start)(void *), void *arg)
189
{
190
	pid_t pid;
191
	struct pam_ctxt *ctx = arg;
192
193
	sshpam_thread_status = -1;
194
	switch ((pid = fork())) {
195
	case -1:
196
		error("fork(): %s", strerror(errno));
197
		return (-1);
198
	case 0:
199
		close(ctx->pam_psock);
200
		ctx->pam_psock = -1;
201
		thread_start(arg);
202
		_exit(1);
203
	default:
204
		*thread = pid;
205
		close(ctx->pam_csock);
206
		ctx->pam_csock = -1;
207
		sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
208
		return (0);
209
	}
210
}
211
212
static int
213
pthread_cancel(sp_pthread_t thread)
214
{
215
	signal(SIGCHLD, sshpam_oldsig);
216
	return (kill(thread, SIGTERM));
217
}
218
219
/* ARGSUSED */
220
static int
221
pthread_join(sp_pthread_t thread, void **value)
222
{
223
	int status;
224
225
	if (sshpam_thread_status != -1)
226
		return (sshpam_thread_status);
227
	signal(SIGCHLD, sshpam_oldsig);
228
	while (waitpid(thread, &status, 0) == -1) {
229
		if (errno == EINTR)
230
			continue;
231
		fatal("%s: waitpid: %s", __func__, strerror(errno));
232
	}
233
	return (status);
234
}
165
}
235
#endif
236
237
166
238
static pam_handle_t *sshpam_handle = NULL;
167
static pam_handle_t *sshpam_handle = NULL;
239
static int sshpam_err = 0;
168
static int sshpam_err = 0;
Lines 303-357 sshpam_password_change_required(int reqd) Link Here
303
	}
232
	}
304
}
233
}
305
234
306
/* Import regular and PAM environment from subprocess */
307
static void
308
import_environments(Buffer *b)
309
{
310
	char *env;
311
	u_int i, num_env;
312
	int err;
313
314
	debug3("PAM: %s entering", __func__);
315
316
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
317
	/* Import variables set by do_pam_account */
318
	sshpam_account_status = buffer_get_int(b);
319
	sshpam_password_change_required(buffer_get_int(b));
320
321
	/* Import environment from subprocess */
322
	num_env = buffer_get_int(b);
323
	if (num_env > 1024)
324
		fatal("%s: received %u environment variables, expected <= 1024",
325
		    __func__, num_env);
326
	sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
327
	debug3("PAM: num env strings %d", num_env);
328
	for(i = 0; i < num_env; i++)
329
		sshpam_env[i] = buffer_get_string(b, NULL);
330
331
	sshpam_env[num_env] = NULL;
332
333
	/* Import PAM environment from subprocess */
334
	num_env = buffer_get_int(b);
335
	debug("PAM: num PAM env strings %d", num_env);
336
	for(i = 0; i < num_env; i++) {
337
		env = buffer_get_string(b, NULL);
338
339
#ifdef HAVE_PAM_PUTENV
340
		/* Errors are not fatal here */
341
		if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
342
			error("PAM: pam_putenv: %s",
343
			    pam_strerror(sshpam_handle, sshpam_err));
344
		}
345
#endif
346
	}
347
#endif
348
}
349
350
/*
235
/*
351
 * Conversation function for authentication thread.
236
 * Conversation function for keyboard-interactive authentication.
352
 */
237
 */
353
static int
238
static int
354
sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
239
sshpam_child_conv(int n, sshpam_const struct pam_message **msg,
355
    struct pam_response **resp, void *data)
240
    struct pam_response **resp, void *data)
356
{
241
{
357
	Buffer buffer;
242
	Buffer buffer;
Lines 416-463 sshpam_thread_conv(int n, sshpam_const struct pam_message **msg, Link Here
416
}
301
}
417
302
418
/*
303
/*
419
 * Authentication thread.
304
 * Terminates the call back child.
305
 *
306
 * Sends a message of type PAM_SUCCESS or PAM_AUTH_ERR to the child.
307
 * In response receives a message with remaining PAM prompts.
308
 * When not using privilege separation, receives serialized packet state too.
309
 *
310
 * After that, the child exits.
420
 */
311
 */
421
static void *
312
void
422
sshpam_thread(void *ctxtp)
313
relieve_from_duty(struct pam_ctxt *ctxt)
423
{
314
{
424
	struct pam_ctxt *ctxt = ctxtp;
425
	Buffer buffer;
315
	Buffer buffer;
426
	struct pam_conv sshpam_conv;
316
	struct ssh *ssh = active_state;
427
	int flags = (options.permit_empty_passwd == 0 ?
317
	int r;
428
	    PAM_DISALLOW_NULL_AUTHTOK : 0);
318
	u_char type;
429
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
319
	char *msg;
430
	extern char **environ;
320
	u_int len;
431
	char **env_from_pam;
432
	u_int i;
433
	const char *pam_user;
434
	const char **ptr_pam_user = &pam_user;
435
	char *tz = getenv("TZ");
436
437
	sshpam_err = pam_get_item(sshpam_handle, PAM_USER,
438
	    (sshpam_const void **)ptr_pam_user);
439
	if (sshpam_err != PAM_SUCCESS)
440
		goto auth_fail;
441
321
442
	environ[0] = NULL;
322
	buffer_init(&buffer);
443
	if (tz != NULL)
323
	buffer_put_cstring(&buffer, "OK");
444
		if (setenv("TZ", tz, 1) == -1)
324
	type = (ctxt->pam_done == 1) ? PAM_SUCCESS : PAM_AUTH_ERR;
445
			error("PAM: could not set TZ environment: %s",
325
	if (ssh_msg_send(ctxt->pam_csock, type, &buffer) == -1) {
446
			    strerror(errno));
326
		buffer_free(&buffer);
327
		fatal("%s: cannnot terminate callback child (send)", __func__);
328
	}
447
329
448
	if (sshpam_authctxt != NULL) {
330
	buffer_clear(&buffer);
449
		setproctitle("%s [pam]",
331
	if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) {
450
		    sshpam_authctxt->valid ? pam_user : "unknown");
332
		buffer_free(&buffer);
333
		fatal("%s: cannnot terminate callback child (receive)",
334
		    __func__);
451
	}
335
	}
452
#endif
336
	type = buffer_get_char(&buffer);
337
	msg = buffer_get_cstring(&buffer, &len);
338
	if (len)
339
		buffer_append(&loginmsg, msg, len);
340
	/* if not using privsep child, sync packet state from callback child */	
341
	if (!use_privsep) {
342
		if ((r = ssh_packet_set_state(ssh, &buffer)) != 0)
343
			fatal("%s: set_state failed: %s",
344
			   __func__, ssh_err(r));
345
	}
346
	free(msg);
347
	buffer_free(&buffer);
348
	close(ctxt->pam_csock);
349
	ctxt->pam_csock = -1;
350
}
351
352
int
353
get_pam_done(void *ctxt)
354
{
355
	struct pam_ctxt *pctxt = (struct pam_ctxt *)ctxt;
356
	return (pctxt->pam_done);
357
}
453
358
454
	sshpam_conv.conv = sshpam_thread_conv;
359
/*
360
 * Perform PAM authentication.
361
 *
362
 * PAM APIs (pam_authenticate, pam_acct_mgmt, ...) block and call the
363
 * provided callback conversation function (sshpam_conv). The conversation
364
 * function sends messages to the callback child (pam_ctxt.pam_child), which
365
 * communicates with the client directly, or indirectly through privsep child.
366
 */
367
void
368
do_pam_auth(struct pam_ctxt *ctxt)
369
{
370
	struct pam_conv sshpam_conv;
371
	int flags = (options.permit_empty_passwd == 0 ?
372
	    PAM_DISALLOW_NULL_AUTHTOK : 0);
373
	struct ssh *ssh = active_state; /* XXX */
374
375
	sshpam_conv.conv = sshpam_child_conv;
455
	sshpam_conv.appdata_ptr = ctxt;
376
	sshpam_conv.appdata_ptr = ctxt;
456
377
378
	ctxt->pam_done = -1;
379
457
	if (sshpam_authctxt == NULL)
380
	if (sshpam_authctxt == NULL)
458
		fatal("%s: PAM authctxt not initialized", __func__);
381
		fatal("%s: PAM authctxt not initialized", __func__);
459
382
460
	buffer_init(&buffer);
461
	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
383
	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
462
	    (const void *)&sshpam_conv);
384
	    (const void *)&sshpam_conv);
463
	if (sshpam_err != PAM_SUCCESS)
385
	if (sshpam_err != PAM_SUCCESS)
Lines 482-544 sshpam_thread(void *ctxtp) Link Here
482
		}
404
		}
483
	}
405
	}
484
406
485
	buffer_put_cstring(&buffer, "OK");
407
	ctxt->pam_done = 1;
486
487
#ifndef UNSUPPORTED_POSIX_THREADS_HACK
488
	/* Export variables set by do_pam_account */
489
	buffer_put_int(&buffer, sshpam_account_status);
490
	buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
491
492
	/* Export any environment strings set in child */
493
	for(i = 0; environ[i] != NULL; i++)
494
		; /* Count */
495
	buffer_put_int(&buffer, i);
496
	for(i = 0; environ[i] != NULL; i++)
497
		buffer_put_cstring(&buffer, environ[i]);
498
499
	/* Export any environment strings set by PAM in child */
500
	env_from_pam = pam_getenvlist(sshpam_handle);
501
	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
502
		; /* Count */
503
	buffer_put_int(&buffer, i);
504
	for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
505
		buffer_put_cstring(&buffer, env_from_pam[i]);
506
#endif /* UNSUPPORTED_POSIX_THREADS_HACK */
507
508
	/* XXX - can't do much about an error here */
509
	ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
510
	buffer_free(&buffer);
511
	pthread_exit(NULL);
512
408
513
 auth_fail:
409
 auth_fail:
514
	buffer_put_cstring(&buffer,
410
	if (sshpam_err != PAM_SUCCESS)
515
	    pam_strerror(sshpam_handle, sshpam_err));
411
		error("PAM: %s for %s%.100s from %.100s",
516
	/* XXX - can't do much about an error here */
412
		    pam_strerror(sshpam_handle, sshpam_err),
517
	if (sshpam_err == PAM_ACCT_EXPIRED)
413
		    sshpam_authctxt->valid ? "" : "illegal user ",
518
		ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer);
414
		    sshpam_authctxt->user,
519
	else if (sshpam_maxtries_reached)
415
		    auth_get_canonical_hostname(ssh, options.use_dns));
520
		ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, &buffer);
416
	relieve_from_duty(ctxt);
521
	else
522
		ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
523
	buffer_free(&buffer);
524
	pthread_exit(NULL);
525
526
	return (NULL); /* Avoid warning for non-pthread case */
527
}
417
}
528
418
529
void
419
void
530
sshpam_thread_cleanup(void)
420
sshpam_child_cleanup(void)
531
{
421
{
532
	struct pam_ctxt *ctxt = cleanup_ctxt;
422
	struct pam_ctxt *ctxt = cleanup_ctxt;
533
423
534
	debug3("PAM: %s entering", __func__);
424
	debug3("PAM: %s entering", __func__);
535
	if (ctxt != NULL && ctxt->pam_thread != 0) {
425
	if (ctxt != NULL && ctxt->pam_child != 0) {
536
		pthread_cancel(ctxt->pam_thread);
426
		signal(SIGCHLD, sshpam_oldsig);
537
		pthread_join(ctxt->pam_thread, NULL);
427
		/* callback child should have had exited by now */
538
		close(ctxt->pam_psock);
428
		kill(ctxt->pam_child, SIGTERM);
539
		close(ctxt->pam_csock);
429
		if (ctxt->pam_psock != -1)
540
		memset(ctxt, 0, sizeof(*ctxt));
430
			close(ctxt->pam_psock);
541
		cleanup_ctxt = NULL;
431
		if (ctxt->pam_csock != -1)
432
			close(ctxt->pam_csock);
433
		if (sshpam_child_status == -1)
434
			waitpid(ctxt->pam_child, &sshpam_child_status, 0);
435
 		cleanup_ctxt = NULL;
542
	}
436
	}
543
}
437
}
544
438
Lines 673-678 sshpam_init_ctx(Authctxt *authctxt) Link Here
673
{
567
{
674
	struct pam_ctxt *ctxt;
568
	struct pam_ctxt *ctxt;
675
	int socks[2];
569
	int socks[2];
570
	pid_t pid;
676
571
677
	debug3("PAM: %s entering", __func__);
572
	debug3("PAM: %s entering", __func__);
678
	/*
573
	/*
Lines 690-696 sshpam_init_ctx(Authctxt *authctxt) Link Here
690
585
691
	ctxt = xcalloc(1, sizeof *ctxt);
586
	ctxt = xcalloc(1, sizeof *ctxt);
692
587
693
	/* Start the authentication thread */
588
	/* Fork the callback child and start PAM authentication */
694
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
589
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
695
		error("PAM: failed create sockets: %s", strerror(errno));
590
		error("PAM: failed create sockets: %s", strerror(errno));
696
		free(ctxt);
591
		free(ctxt);
Lines 698-712 sshpam_init_ctx(Authctxt *authctxt) Link Here
698
	}
593
	}
699
	ctxt->pam_psock = socks[0];
594
	ctxt->pam_psock = socks[0];
700
	ctxt->pam_csock = socks[1];
595
	ctxt->pam_csock = socks[1];
701
	if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {
596
702
		error("PAM: failed to start authentication thread: %s",
597
	sshpam_child_status = -1;
703
		    strerror(errno));
598
	switch ((pid = fork())) {
599
	case -1:
600
		error("fork(): %s", strerror(errno));
704
		close(socks[0]);
601
		close(socks[0]);
705
		close(socks[1]);
602
		close(socks[1]);
706
		free(ctxt);
603
		free(ctxt);
707
		return (NULL);
604
		return (NULL);
605
	case 0:
606
		/* child processes query & respond for kbdint */
607
		close(ctxt->pam_csock);
608
		ctxt->pam_csock = -1;
609
		break;
610
	default:
611
		/* parent does PAM */
612
		ctxt->pam_child = pid;
613
		close(ctxt->pam_psock);
614
		ctxt->pam_psock = -1;
615
		sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
616
		cleanup_ctxt = ctxt;
617
		do_pam_auth(ctxt);
708
	}
618
	}
709
	cleanup_ctxt = ctxt;
710
	return (ctxt);
619
	return (ctxt);
711
}
620
}
712
621
Lines 721-728 sshpam_query(void *ctx, char **name, char **info, Link Here
721
	u_char type;
630
	u_char type;
722
	char *msg;
631
	char *msg;
723
	size_t len, mlen;
632
	size_t len, mlen;
633
	int r;
724
634
725
	debug3("PAM: %s entering", __func__);
635
	debug3("PAM: %s entering", __func__);
636
726
	buffer_init(&buffer);
637
	buffer_init(&buffer);
727
	*name = xstrdup("");
638
	*name = xstrdup("");
728
	*info = xstrdup("");
639
	*info = xstrdup("");
Lines 730-735 sshpam_query(void *ctx, char **name, char **info, Link Here
730
	**prompts = NULL;
641
	**prompts = NULL;
731
	plen = 0;
642
	plen = 0;
732
	*echo_on = xmalloc(sizeof(u_int));
643
	*echo_on = xmalloc(sizeof(u_int));
644
645
	/* in case PAM was already done in callback child */
646
	switch (ctxt->pam_done) {
647
	case 1:
648
		return (0);
649
	case 0:
650
		break;
651
	default:
652
		return (-1);
653
	}
654
733
	while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
655
	while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
734
		type = buffer_get_char(&buffer);
656
		type = buffer_get_char(&buffer);
735
		msg = buffer_get_string(&buffer, NULL);
657
		msg = buffer_get_string(&buffer, NULL);
Lines 765-779 sshpam_query(void *ctx, char **name, char **info, Link Here
765
			/* FALLTHROUGH */
687
			/* FALLTHROUGH */
766
		case PAM_AUTH_ERR:
688
		case PAM_AUTH_ERR:
767
			debug3("PAM: %s", pam_strerror(sshpam_handle, type));
689
			debug3("PAM: %s", pam_strerror(sshpam_handle, type));
768
			if (**prompts != NULL && strlen(**prompts) != 0) {
769
				*info = **prompts;
770
				**prompts = NULL;
771
				*num = 0;
772
				**echo_on = 0;
773
				ctxt->pam_done = -1;
774
				free(msg);
775
				return 0;
776
			}
777
			/* FALLTHROUGH */
690
			/* FALLTHROUGH */
778
		case PAM_SUCCESS:
691
		case PAM_SUCCESS:
779
			if (**prompts != NULL) {
692
			if (**prompts != NULL) {
Lines 784-808 sshpam_query(void *ctx, char **name, char **info, Link Here
784
				free(**prompts);
697
				free(**prompts);
785
				**prompts = NULL;
698
				**prompts = NULL;
786
			}
699
			}
787
			if (type == PAM_SUCCESS) {
700
			/* send accumulated messages to parent */
788
				if (!sshpam_authctxt->valid ||
701
			buffer_clear(&buffer);
789
				    (sshpam_authctxt->pw->pw_uid == 0 &&
702
			buffer_put_cstring(&buffer, buffer_ptr(&loginmsg));
790
				    options.permit_root_login != PERMIT_YES))
703
			if (!use_privsep) {
791
					fatal("Internal error: PAM auth "
704
				/* sync packet state with parrent */
792
					    "succeeded when it should have "
705
				r = ssh_packet_get_state(ssh, &buffer);
793
					    "failed");
706
				if (r != 0)
794
				import_environments(&buffer);
707
					fatal("%s: get_state failed: %s",
795
				*num = 0;
708
					    __func__, ssh_err(r));
796
				**echo_on = 0;
797
				ctxt->pam_done = 1;
798
				free(msg);
799
				return (0);
800
			}
709
			}
801
			error("PAM: %s for %s%.100s from %.100s", msg,
710
			ssh_msg_send(ctxt->pam_psock, type, &buffer);
802
			    sshpam_authctxt->valid ? "" : "illegal user ",
711
			/* callback child ends here */
803
			    sshpam_authctxt->user,
712
			close(ctxt->pam_psock);
804
			    auth_get_canonical_hostname(ssh, options.use_dns));
713
			exit(0);
805
			/* FALLTHROUGH */
806
		default:
714
		default:
807
			*num = 0;
715
			*num = 0;
808
			**echo_on = 0;
716
			**echo_on = 0;
Lines 882-888 sshpam_free_ctx(void *ctxtp) Link Here
882
	struct pam_ctxt *ctxt = ctxtp;
790
	struct pam_ctxt *ctxt = ctxtp;
883
791
884
	debug3("PAM: %s entering", __func__);
792
	debug3("PAM: %s entering", __func__);
885
	sshpam_thread_cleanup();
793
	sshpam_child_cleanup();
886
	free(ctxt);
794
	free(ctxt);
887
	/*
795
	/*
888
	 * We don't call sshpam_cleanup() here because we may need the PAM
796
	 * We don't call sshpam_cleanup() here because we may need the PAM
(-)a/auth-pam.h (-1 / +2 lines)
Lines 35-41 int do_pam_putenv(char *, char *); Link Here
35
char ** fetch_pam_environment(void);
35
char ** fetch_pam_environment(void);
36
char ** fetch_pam_child_environment(void);
36
char ** fetch_pam_child_environment(void);
37
void free_pam_environment(char **);
37
void free_pam_environment(char **);
38
void sshpam_thread_cleanup(void);
38
void sshpam_child_cleanup(void);
39
int get_pam_done(void *);
39
void sshpam_cleanup(void);
40
void sshpam_cleanup(void);
40
int sshpam_auth_passwd(Authctxt *, const char *);
41
int sshpam_auth_passwd(Authctxt *, const char *);
41
int sshpam_get_maxtries_reached(void);
42
int sshpam_get_maxtries_reached(void);
(-)a/monitor.c (-1 / +29 lines)
Lines 1008-1013 mm_answer_pam_init_ctx(int sock, Buffer *m) Link Here
1008
	sshpam_ctxt = (sshpam_device.init_ctx)(authctxt);
1008
	sshpam_ctxt = (sshpam_device.init_ctx)(authctxt);
1009
	sshpam_authok = NULL;
1009
	sshpam_authok = NULL;
1010
	buffer_clear(m);
1010
	buffer_clear(m);
1011
	int pam_done = 0;
1011
	if (sshpam_ctxt != NULL) {
1012
	if (sshpam_ctxt != NULL) {
1012
		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
1013
		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
1013
		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_QUERY, 1);
1014
		monitor_permit(mon_dispatch, MONITOR_REQ_PAM_QUERY, 1);
Lines 1015-1020 mm_answer_pam_init_ctx(int sock, Buffer *m) Link Here
1015
	} else {
1016
	} else {
1016
		buffer_put_int(m, 0);
1017
		buffer_put_int(m, 0);
1017
	}
1018
	}
1019
1020
	/* pam conversation successfully finished in child process */
1021
	if (sshpam_ctxt != NULL && 
1022
	    (pam_done = get_pam_done(sshpam_ctxt)) != 0) {
1023
		auth_method = "keyboard-interactive";
1024
		auth_submethod = "pam";
1025
		/* 
1026
		 * ANS_PAM_INIT_CTX already sent by callback child.
1027
		 * Privsep child now expects ANS_PAM_QUERY.
1028
		 */
1029
		buffer_clear(m);
1030
		buffer_put_int(m, 0);		/* ret */
1031
		buffer_put_cstring(m, "");	/* name */
1032
		if (pam_done == 1) {		/* info */
1033
			buffer_put_cstring(m, "");
1034
		} else {
1035
			buffer_put_string(m, buffer_ptr(&loginmsg),
1036
			    buffer_len(&loginmsg));
1037
			buffer_clear(&loginmsg);
1038
		}
1039
		buffer_put_int(m, sshpam_get_maxtries_reached());
1040
		buffer_put_int(m, 0);		/* num */
1041
		mm_request_send(sock, MONITOR_ANS_PAM_QUERY, m);
1042
		return (0);
1043
	}
1044
1018
	mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m);
1045
	mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m);
1019
	return (0);
1046
	return (0);
1020
}
1047
}
Lines 1581-1587 monitor_apply_keystate(struct monitor *pmonitor) Link Here
1581
	int r;
1608
	int r;
1582
1609
1583
	debug3("%s: packet_set_state", __func__);
1610
	debug3("%s: packet_set_state", __func__);
1584
	if ((r = ssh_packet_set_state(ssh, child_state)) != 0)
1611
	if ((r = ssh_packet_set_state(ssh, child_state)) != 0 ||
1612
	    (r = ssh_packet_set_postauth(ssh)) != 0)
1585
                fatal("%s: packet_set_state: %s", __func__, ssh_err(r));
1613
                fatal("%s: packet_set_state: %s", __func__, ssh_err(r));
1586
	sshbuf_free(child_state);
1614
	sshbuf_free(child_state);
1587
	child_state = NULL;
1615
	child_state = NULL;
(-)a/packet.c (-1 / +1 lines)
Lines 2439-2445 ssh_packet_get_output(struct ssh *ssh) Link Here
2439
}
2439
}
2440
2440
2441
/* Reset after_authentication and reset compression in post-auth privsep */
2441
/* Reset after_authentication and reset compression in post-auth privsep */
2442
static int
2442
int
2443
ssh_packet_set_postauth(struct ssh *ssh)
2443
ssh_packet_set_postauth(struct ssh *ssh)
2444
{
2444
{
2445
	int r;
2445
	int r;
(-)a/packet.h (+1 lines)
Lines 148-153 u_int ssh_packet_get_maxsize(struct ssh *); Link Here
148
148
149
int	 ssh_packet_get_state(struct ssh *, struct sshbuf *);
149
int	 ssh_packet_get_state(struct ssh *, struct sshbuf *);
150
int	 ssh_packet_set_state(struct ssh *, struct sshbuf *);
150
int	 ssh_packet_set_state(struct ssh *, struct sshbuf *);
151
int	 ssh_packet_set_postauth(struct ssh *ssh);
151
152
152
const char *ssh_remote_ipaddr(struct ssh *);
153
const char *ssh_remote_ipaddr(struct ssh *);
153
int	 ssh_remote_port(struct ssh *);
154
int	 ssh_remote_port(struct ssh *);
(-)a/servconf.c (+12 lines)
Lines 374-379 fill_default_server_options(ServerOptions *options) Link Here
374
		options->compression = 0;
374
		options->compression = 0;
375
	}
375
	}
376
#endif
376
#endif
377
#ifdef USE_PAM
378
	if (!use_privsep && options->compression == COMP_ZLIB && 
379
	    options->use_pam && 
380
	    (options->kbd_interactive_authentication || 
381
	     options->challenge_response_authentication)) {
382
		error("Compression algorithm 'zlib' is not supported for "
383
		    "PAM authentication when privilege separation is off");
384
		error("Limmiting compression algorithms to "
385
		    "'none,zlib@openssh.com'");
386
		options->compression = COMP_DELAYED;
387
	}
388
#endif
377
389
378
}
390
}
379
391
(-)a/session.c (-2 / +1 lines)
Lines 2535-2541 do_cleanup(Authctxt *authctxt) Link Here
2535
#ifdef USE_PAM
2535
#ifdef USE_PAM
2536
	if (options.use_pam) {
2536
	if (options.use_pam) {
2537
		sshpam_cleanup();
2537
		sshpam_cleanup();
2538
		sshpam_thread_cleanup();
2538
		sshpam_child_cleanup();
2539
	}
2539
	}
2540
#endif
2540
#endif
2541
2541
2542
- 

Return to bug 2548