summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2003-05-10 19:28:02 +1000
committerDamien Miller <djm@mindrot.org>2003-05-10 19:28:02 +1000
commit4f9f42a9bb6a6aa8f6100d873dc6344f2f9994de (patch)
treef81c39146e1cfabb4b198f57f60453b2dcaac299
parentc437cda328b4733b59a7ed028b72e6b7f58f86e6 (diff)
- (djm) Merge FreeBSD PAM code: replaces PAM password auth kludge with
proper challenge-response module
-rw-r--r--ChangeLog4
-rw-r--r--Makefile.in4
-rw-r--r--auth-chall.c26
-rw-r--r--auth-pam.c895
-rw-r--r--auth-pam.h6
-rw-r--r--auth-passwd.c16
-rw-r--r--auth.h3
-rw-r--r--auth1.c14
-rw-r--r--auth2-chall.c19
-rw-r--r--auth2-kbdint.c4
-rw-r--r--auth2-pam.c165
-rw-r--r--auth2-pam.h8
-rw-r--r--configure.ac4
-rw-r--r--monitor.c113
-rw-r--r--monitor.h5
-rw-r--r--monitor_wrap.c82
-rw-r--r--monitor_wrap.h5
17 files changed, 819 insertions, 554 deletions
diff --git a/ChangeLog b/ChangeLog
index 5b4ff341b..4acedd1a4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,8 @@
3 "make install". Patch by roth@feep.net. 3 "make install". Patch by roth@feep.net.
4 - (dtucker) Bug #536: Test for and work around openpty/controlling tty 4 - (dtucker) Bug #536: Test for and work around openpty/controlling tty
5 problem on Linux (fixes "could not set controlling tty" errors). 5 problem on Linux (fixes "could not set controlling tty" errors).
6 - (djm) Merge FreeBSD PAM code: replaces PAM password auth kludge with
7 proper challenge-response module
6 8
720030504 920030504
8 - (dtucker) Bug #497: Move #include of bsd-cygwin_util.h to openbsd-compat.h. 10 - (dtucker) Bug #497: Move #include of bsd-cygwin_util.h to openbsd-compat.h.
@@ -1376,4 +1378,4 @@
1376 save auth method before monitor_reset_key_state(); bugzilla bug #284; 1378 save auth method before monitor_reset_key_state(); bugzilla bug #284;
1377 ok provos@ 1379 ok provos@
1378 1380
1379$Id: ChangeLog,v 1.2672 2003/05/10 07:05:46 dtucker Exp $ 1381$Id: ChangeLog,v 1.2673 2003/05/10 09:28:02 djm Exp $
diff --git a/Makefile.in b/Makefile.in
index 23a9d413c..670d9b500 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.230 2003/05/10 06:48:23 dtucker Exp $ 1# $Id: Makefile.in,v 1.231 2003/05/10 09:28:02 djm Exp $
2 2
3# uncomment if you run a non bourne compatable shell. Ie. csh 3# uncomment if you run a non bourne compatable shell. Ie. csh
4#SHELL = @SH@ 4#SHELL = @SH@
@@ -81,7 +81,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
81 monitor_mm.o monitor.o monitor_wrap.o monitor_fdpass.o \ 81 monitor_mm.o monitor.o monitor_wrap.o monitor_fdpass.o \
82 kexdhs.o kexgexs.o \ 82 kexdhs.o kexgexs.o \
83 auth-krb5.o auth-krb4.o \ 83 auth-krb5.o auth-krb4.o \
84 loginrec.o auth-pam.o auth2-pam.o auth-sia.o md5crypt.o 84 loginrec.o auth-pam.o auth-sia.o md5crypt.o
85 85
86MANPAGES = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out 86MANPAGES = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
87MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5 87MANPAGES_IN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
diff --git a/auth-chall.c b/auth-chall.c
index 45e0c3452..6b7c8bd13 100644
--- a/auth-chall.c
+++ b/auth-chall.c
@@ -76,7 +76,33 @@ verify_response(Authctxt *authctxt, const char *response)
76 return 0; 76 return 0;
77 resp[0] = (char *)response; 77 resp[0] = (char *)response;
78 res = device->respond(authctxt->kbdintctxt, 1, resp); 78 res = device->respond(authctxt->kbdintctxt, 1, resp);
79 if (res == 1) {
80 /* postponed - send a null query just in case */
81 char *name, *info, **prompts;
82 u_int i, numprompts, *echo_on;
83
84 res = device->query(authctxt->kbdintctxt, &name, &info,
85 &numprompts, &prompts, &echo_on);
86 if (res == 0) {
87 for (i = 0; i < numprompts; i++)
88 xfree(prompts[i]);
89 xfree(prompts);
90 xfree(name);
91 xfree(echo_on);
92 xfree(info);
93 }
94 /* if we received more prompts, we're screwed */
95 res = (numprompts != 0);
96 }
79 device->free_ctx(authctxt->kbdintctxt); 97 device->free_ctx(authctxt->kbdintctxt);
80 authctxt->kbdintctxt = NULL; 98 authctxt->kbdintctxt = NULL;
81 return res ? 0 : 1; 99 return res ? 0 : 1;
82} 100}
101void
102abandon_challenge_response(Authctxt *authctxt)
103{
104 if (authctxt->kbdintctxt != NULL) {
105 device->free_ctx(authctxt->kbdintctxt);
106 authctxt->kbdintctxt = NULL;
107 }
108}
diff --git a/auth-pam.c b/auth-pam.c
index f3d1956ea..f4718035d 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -1,5 +1,11 @@
1/* 1/*-
2 * Copyright (c) 2000 Damien Miller. All rights reserved. 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.
3 * 9 *
4 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
@@ -10,446 +16,633 @@
10 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
12 * 18 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
23 */ 30 */
24 31
25#include "includes.h" 32#include "includes.h"
33RCSID("$FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $");
26 34
27#ifdef USE_PAM 35#ifdef USE_PAM
28#include "xmalloc.h" 36#include <security/pam_appl.h>
29#include "log.h" 37
30#include "auth.h" 38#include "auth.h"
31#include "auth-options.h"
32#include "auth-pam.h" 39#include "auth-pam.h"
33#include "servconf.h" 40#include "buffer.h"
41#include "bufaux.h"
34#include "canohost.h" 42#include "canohost.h"
43#include "log.h"
44#include "monitor_wrap.h"
45#include "msg.h"
46#include "packet.h"
35#include "readpass.h" 47#include "readpass.h"
48#include "servconf.h"
49#include "ssh2.h"
50#include "xmalloc.h"
36 51
37extern char *__progname; 52#define __unused
38
39extern int use_privsep;
40 53
41RCSID("$Id: auth-pam.c,v 1.57 2003/04/29 13:22:40 djm Exp $"); 54#ifdef USE_POSIX_THREADS
55#include <pthread.h>
56/*
57 * Avoid namespace clash when *not* using pthreads for systems *with*
58 * pthreads, which unconditionally define pthread_t via sys/types.h
59 * (e.g. Linux)
60 */
61typedef pthread_t sp_pthread_t;
62#else
63/*
64 * Simulate threads with processes.
65 */
66typedef pid_t sp_pthread_t;
42 67
43#define NEW_AUTHTOK_MSG \ 68static void
44 "Warning: Your password has expired, please change it now." 69pthread_exit(void *value __unused)
45#define NEW_AUTHTOK_MSG_PRIVSEP \ 70{
46 "Your password has expired, the session cannot proceed." 71 _exit(0);
72}
47 73
48static int do_pam_conversation(int num_msg, const struct pam_message **msg, 74static int
49 struct pam_response **resp, void *appdata_ptr); 75pthread_create(sp_pthread_t *thread, const void *attr __unused,
76 void *(*thread_start)(void *), void *arg)
77{
78 pid_t pid;
79
80 switch ((pid = fork())) {
81 case -1:
82 error("fork(): %s", strerror(errno));
83 return (-1);
84 case 0:
85 thread_start(arg);
86 _exit(1);
87 default:
88 *thread = pid;
89 return (0);
90 }
91}
50 92
51/* module-local variables */ 93static int
52static struct pam_conv conv = { 94pthread_cancel(sp_pthread_t thread)
53 (int (*)())do_pam_conversation,
54 NULL
55};
56static char *__pam_msg = NULL;
57static pam_handle_t *__pamh = NULL;
58static const char *__pampasswd = NULL;
59
60/* states for do_pam_conversation() */
61enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
62/* remember whether pam_acct_mgmt() returned PAM_NEW_AUTHTOK_REQD */
63static int password_change_required = 0;
64/* remember whether the last pam_authenticate() succeeded or not */
65static int was_authenticated = 0;
66
67/* Remember what has been initialised */
68static int session_opened = 0;
69static int creds_set = 0;
70
71/* accessor which allows us to switch conversation structs according to
72 * the authentication method being used */
73void do_pam_set_conv(struct pam_conv *conv)
74{ 95{
75 pam_set_item(__pamh, PAM_CONV, conv); 96 return (kill(thread, SIGTERM));
76} 97}
77 98
78/* start an authentication run */ 99static int
79int do_pam_authenticate(int flags) 100pthread_join(sp_pthread_t thread, void **value __unused)
80{ 101{
81 int retval = pam_authenticate(__pamh, flags); 102 int status;
82 was_authenticated = (retval == PAM_SUCCESS); 103
83 return retval; 104 waitpid(thread, &status, 0);
105 return (status);
84} 106}
107#endif
108
109
110static pam_handle_t *sshpam_handle;
111static int sshpam_err;
112static int sshpam_authenticated;
113static int sshpam_new_authtok_reqd;
114static int sshpam_session_open;
115static int sshpam_cred_established;
116
117struct pam_ctxt {
118 sp_pthread_t pam_thread;
119 int pam_psock;
120 int pam_csock;
121 int pam_done;
122};
123
124static void sshpam_free_ctx(void *);
85 125
86/* 126/*
87 * PAM conversation function. 127 * Conversation function for authentication thread.
88 * There are two states this can run in.
89 *
90 * INITIAL_LOGIN mode simply feeds the password from the client into
91 * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output
92 * messages with into __pam_msg. This is used during initial
93 * authentication to bypass the normal PAM password prompt.
94 *
95 * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase()
96 * and outputs messages to stderr. This mode is used if pam_chauthtok()
97 * is called to update expired passwords.
98 */ 128 */
99static int do_pam_conversation(int num_msg, const struct pam_message **msg, 129static int
100 struct pam_response **resp, void *appdata_ptr) 130sshpam_thread_conv(int n,
131 const struct pam_message **msg,
132 struct pam_response **resp,
133 void *data)
101{ 134{
102 struct pam_response *reply; 135 Buffer buffer;
103 int count; 136 struct pam_ctxt *ctxt;
104 char buf[1024]; 137 int i;
105 138
106 /* PAM will free this later */ 139 ctxt = data;
107 reply = xmalloc(num_msg * sizeof(*reply)); 140 if (n <= 0 || n > PAM_MAX_NUM_MSG)
108 141 return (PAM_CONV_ERR);
109 for (count = 0; count < num_msg; count++) { 142 *resp = xmalloc(n * sizeof **resp);
110 if (pamstate == INITIAL_LOGIN) { 143 buffer_init(&buffer);
111 /* 144 for (i = 0; i < n; ++i) {
112 * We can't use stdio yet, queue messages for 145 resp[i]->resp_retcode = 0;
113 * printing later 146 resp[i]->resp = NULL;
114 */ 147 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
115 switch(PAM_MSG_MEMBER(msg, count, msg_style)) { 148 case PAM_PROMPT_ECHO_OFF:
116 case PAM_PROMPT_ECHO_ON: 149 buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg));
117 xfree(reply); 150 ssh_msg_send(ctxt->pam_csock,
118 return PAM_CONV_ERR; 151 PAM_MSG_MEMBER(msg, i, msg_style), &buffer);
119 case PAM_PROMPT_ECHO_OFF: 152 ssh_msg_recv(ctxt->pam_csock, &buffer);
120 if (__pampasswd == NULL) { 153 if (buffer_get_char(&buffer) != PAM_AUTHTOK)
121 xfree(reply); 154 goto fail;
122 return PAM_CONV_ERR; 155 resp[i]->resp = buffer_get_string(&buffer, NULL);
123 } 156 break;
124 reply[count].resp = xstrdup(__pampasswd); 157 case PAM_PROMPT_ECHO_ON:
125 reply[count].resp_retcode = PAM_SUCCESS; 158 buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg));
126 break; 159 ssh_msg_send(ctxt->pam_csock,
127 case PAM_ERROR_MSG: 160 PAM_MSG_MEMBER(msg, i, msg_style), &buffer);
128 case PAM_TEXT_INFO: 161 ssh_msg_recv(ctxt->pam_csock, &buffer);
129 if (PAM_MSG_MEMBER(msg, count, msg) != NULL) { 162 if (buffer_get_char(&buffer) != PAM_AUTHTOK)
130 message_cat(&__pam_msg, 163 goto fail;
131 PAM_MSG_MEMBER(msg, count, msg)); 164 resp[i]->resp = buffer_get_string(&buffer, NULL);
132 } 165 break;
133 reply[count].resp = xstrdup(""); 166 case PAM_ERROR_MSG:
134 reply[count].resp_retcode = PAM_SUCCESS; 167 buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg));
135 break; 168 ssh_msg_send(ctxt->pam_csock,
136 default: 169 PAM_MSG_MEMBER(msg, i, msg_style), &buffer);
137 xfree(reply); 170 break;
138 return PAM_CONV_ERR; 171 case PAM_TEXT_INFO:
139 } 172 buffer_put_cstring(&buffer, PAM_MSG_MEMBER(msg, i, msg));
140 } else { 173 ssh_msg_send(ctxt->pam_csock,
141 /* 174 PAM_MSG_MEMBER(msg, i, msg_style), &buffer);
142 * stdio is connected, so interact directly 175 break;
143 */ 176 default:
144 switch(PAM_MSG_MEMBER(msg, count, msg_style)) { 177 goto fail;
145 case PAM_PROMPT_ECHO_ON:
146 fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
147 fgets(buf, sizeof(buf), stdin);
148 reply[count].resp = xstrdup(buf);
149 reply[count].resp_retcode = PAM_SUCCESS;
150 break;
151 case PAM_PROMPT_ECHO_OFF:
152 reply[count].resp =
153 read_passphrase(PAM_MSG_MEMBER(msg, count,
154 msg), RP_ALLOW_STDIN);
155 reply[count].resp_retcode = PAM_SUCCESS;
156 break;
157 case PAM_ERROR_MSG:
158 case PAM_TEXT_INFO:
159 if (PAM_MSG_MEMBER(msg, count, msg) != NULL)
160 fprintf(stderr, "%s\n",
161 PAM_MSG_MEMBER(msg, count, msg));
162 reply[count].resp = xstrdup("");
163 reply[count].resp_retcode = PAM_SUCCESS;
164 break;
165 default:
166 xfree(reply);
167 return PAM_CONV_ERR;
168 }
169 } 178 }
179 buffer_clear(&buffer);
170 } 180 }
181 buffer_free(&buffer);
182 return (PAM_SUCCESS);
183 fail:
184 while (i)
185 xfree(resp[--i]);
186 xfree(*resp);
187 *resp = NULL;
188 buffer_free(&buffer);
189 return (PAM_CONV_ERR);
190}
171 191
172 *resp = reply; 192/*
193 * Authentication thread.
194 */
195static void *
196sshpam_thread(void *ctxtp)
197{
198 struct pam_ctxt *ctxt = ctxtp;
199 Buffer buffer;
200 struct pam_conv sshpam_conv = { sshpam_thread_conv, ctxt };
201#ifndef USE_POSIX_THREADS
202 const char *pam_user;
203
204 pam_get_item(sshpam_handle, PAM_USER, (const void **)&pam_user);
205 setproctitle("%s [pam]", pam_user);
206#endif
173 207
174 return PAM_SUCCESS; 208 buffer_init(&buffer);
209 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
210 (const void *)&sshpam_conv);
211 if (sshpam_err != PAM_SUCCESS)
212 goto auth_fail;
213 sshpam_err = pam_authenticate(sshpam_handle, 0);
214 if (sshpam_err != PAM_SUCCESS)
215 goto auth_fail;
216 sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
217 if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD)
218 goto auth_fail;
219 buffer_put_cstring(&buffer, "OK");
220 ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
221 buffer_free(&buffer);
222 pthread_exit(NULL);
223
224 auth_fail:
225 buffer_put_cstring(&buffer,
226 pam_strerror(sshpam_handle, sshpam_err));
227 ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
228 buffer_free(&buffer);
229 pthread_exit(NULL);
230
231 return (NULL); /* Avoid warning for non-pthread case */
175} 232}
176 233
177/* Called at exit to cleanly shutdown PAM */ 234static void
178void do_pam_cleanup_proc(void *context) 235sshpam_thread_cleanup(void *ctxtp)
179{ 236{
180 int pam_retval = PAM_SUCCESS; 237 struct pam_ctxt *ctxt = ctxtp;
181 238
182 if (__pamh && session_opened) { 239 pthread_cancel(ctxt->pam_thread);
183 pam_retval = pam_close_session(__pamh, 0); 240 pthread_join(ctxt->pam_thread, NULL);
184 if (pam_retval != PAM_SUCCESS) 241 close(ctxt->pam_psock);
185 logit("Cannot close PAM session[%d]: %.200s", 242 close(ctxt->pam_csock);
186 pam_retval, PAM_STRERROR(__pamh, pam_retval)); 243}
187 }
188 244
189 if (__pamh && creds_set) { 245static int
190 pam_retval = pam_setcred(__pamh, PAM_DELETE_CRED); 246sshpam_null_conv(int n,
191 if (pam_retval != PAM_SUCCESS) 247 const struct pam_message **msg,
192 debug("Cannot delete credentials[%d]: %.200s", 248 struct pam_response **resp,
193 pam_retval, PAM_STRERROR(__pamh, pam_retval)); 249 void *data)
194 } 250{
251
252 return (PAM_CONV_ERR);
253}
195 254
196 if (__pamh) { 255static struct pam_conv null_conv = { sshpam_null_conv, NULL };
197 pam_retval = pam_end(__pamh, pam_retval); 256
198 if (pam_retval != PAM_SUCCESS) 257static void
199 logit("Cannot release PAM authentication[%d]: %.200s", 258sshpam_cleanup(void *arg)
200 pam_retval, PAM_STRERROR(__pamh, pam_retval)); 259{
260 (void)arg;
261 debug("PAM: cleanup");
262 pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
263 if (sshpam_cred_established) {
264 pam_setcred(sshpam_handle, PAM_DELETE_CRED);
265 sshpam_cred_established = 0;
266 }
267 if (sshpam_session_open) {
268 pam_close_session(sshpam_handle, PAM_SILENT);
269 sshpam_session_open = 0;
201 } 270 }
271 sshpam_authenticated = sshpam_new_authtok_reqd = 0;
272 pam_end(sshpam_handle, sshpam_err);
273 sshpam_handle = NULL;
202} 274}
203 275
204/* Attempt password authentication using PAM */ 276static int
205int auth_pam_password(Authctxt *authctxt, const char *password) 277sshpam_init(const char *user)
206{ 278{
207 extern ServerOptions options; 279 extern ServerOptions options;
208 int pam_retval; 280 extern u_int utmp_len;
209 struct passwd *pw = authctxt->pw; 281 const char *pam_rhost, *pam_user;
210 282
211 do_pam_set_conv(&conv); 283 if (sshpam_handle != NULL) {
212 284 /* We already have a PAM context; check if the user matches */
213 __pampasswd = password; 285 sshpam_err = pam_get_item(sshpam_handle,
214 286 PAM_USER, (const void **)&pam_user);
215 pamstate = INITIAL_LOGIN; 287 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
216 pam_retval = do_pam_authenticate( 288 return (0);
217 options.permit_empty_passwd == 0 ? PAM_DISALLOW_NULL_AUTHTOK : 0); 289 fatal_remove_cleanup(sshpam_cleanup, NULL);
218 if (pam_retval == PAM_SUCCESS && pw) { 290 pam_end(sshpam_handle, sshpam_err);
219 debug("PAM password authentication accepted for " 291 sshpam_handle = NULL;
220 "%.100s", pw->pw_name); 292 }
221 return 1; 293 debug("PAM: initializing for \"%s\"", user);
222 } else { 294 sshpam_err = pam_start("sshd", user, &null_conv, &sshpam_handle);
223 debug("PAM password authentication failed for " 295 if (sshpam_err != PAM_SUCCESS)
224 "%.100s: %s", pw ? pw->pw_name : "an illegal user", 296 return (-1);
225 PAM_STRERROR(__pamh, pam_retval)); 297 pam_rhost = get_remote_name_or_ip(utmp_len,
226 return 0; 298 options.verify_reverse_mapping);
299 debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
300 sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);
301 if (sshpam_err != PAM_SUCCESS) {
302 pam_end(sshpam_handle, sshpam_err);
303 sshpam_handle = NULL;
304 return (-1);
227 } 305 }
306 fatal_add_cleanup(sshpam_cleanup, NULL);
307 return (0);
228} 308}
229 309
230/* Do account management using PAM */ 310static void *
231int do_pam_account(char *username, char *remote_user) 311sshpam_init_ctx(Authctxt *authctxt)
232{ 312{
233 int pam_retval; 313 struct pam_ctxt *ctxt;
314 int socks[2];
234 315
235 do_pam_set_conv(&conv); 316 /* Initialize PAM */
317 if (sshpam_init(authctxt->user) == -1) {
318 error("PAM: initialization failed");
319 return (NULL);
320 }
236 321
237 if (remote_user) { 322 ctxt = xmalloc(sizeof *ctxt);
238 debug("PAM setting ruser to \"%.200s\"", remote_user); 323 ctxt->pam_done = 0;
239 pam_retval = pam_set_item(__pamh, PAM_RUSER, remote_user); 324
240 if (pam_retval != PAM_SUCCESS) 325 /* Start the authentication thread */
241 fatal("PAM set ruser failed[%d]: %.200s", pam_retval, 326 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
242 PAM_STRERROR(__pamh, pam_retval)); 327 error("PAM: failed create sockets: %s", strerror(errno));
328 xfree(ctxt);
329 return (NULL);
330 }
331 ctxt->pam_psock = socks[0];
332 ctxt->pam_csock = socks[1];
333 if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {
334 error("PAM: failed to start authentication thread: %s",
335 strerror(errno));
336 close(socks[0]);
337 close(socks[1]);
338 xfree(ctxt);
339 return (NULL);
243 } 340 }
341 fatal_add_cleanup(sshpam_thread_cleanup, ctxt);
342 return (ctxt);
343}
244 344
245 pam_retval = pam_acct_mgmt(__pamh, 0); 345static int
246 debug2("pam_acct_mgmt() = %d", pam_retval); 346sshpam_query(void *ctx, char **name, char **info,
247 switch (pam_retval) { 347 u_int *num, char ***prompts, u_int **echo_on)
248 case PAM_SUCCESS: 348{
249 /* This is what we want */ 349 Buffer buffer;
350 struct pam_ctxt *ctxt = ctx;
351 size_t plen;
352 u_char type;
353 char *msg;
354
355 buffer_init(&buffer);
356 *name = xstrdup("");
357 *info = xstrdup("");
358 *prompts = xmalloc(sizeof(char *));
359 **prompts = NULL;
360 plen = 0;
361 *echo_on = xmalloc(sizeof(u_int));
362 while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
363 type = buffer_get_char(&buffer);
364 msg = buffer_get_string(&buffer, NULL);
365 switch (type) {
366 case PAM_PROMPT_ECHO_ON:
367 case PAM_PROMPT_ECHO_OFF:
368 *num = 1;
369 **prompts = xrealloc(**prompts, plen + strlen(msg) + 1);
370 plen += sprintf(**prompts + plen, "%s", msg);
371 **echo_on = (type == PAM_PROMPT_ECHO_ON);
372 xfree(msg);
373 return (0);
374 case PAM_ERROR_MSG:
375 case PAM_TEXT_INFO:
376 /* accumulate messages */
377 **prompts = xrealloc(**prompts, plen + strlen(msg) + 1);
378 plen += sprintf(**prompts + plen, "%s", msg);
379 xfree(msg);
250 break; 380 break;
251#if 0
252 case PAM_NEW_AUTHTOK_REQD: 381 case PAM_NEW_AUTHTOK_REQD:
253 message_cat(&__pam_msg, use_privsep ? 382 sshpam_new_authtok_reqd = 1;
254 NEW_AUTHTOK_MSG_PRIVSEP : NEW_AUTHTOK_MSG); 383 /* FALLTHROUGH */
255 /* flag that password change is necessary */ 384 case PAM_SUCCESS:
256 password_change_required = 1; 385 case PAM_AUTH_ERR:
257 /* disallow other functionality for now */ 386 if (**prompts != NULL) {
258 no_port_forwarding_flag |= 2; 387 /* drain any accumulated messages */
259 no_agent_forwarding_flag |= 2; 388#if 0 /* XXX - not compatible with privsep */
260 no_x11_forwarding_flag |= 2; 389 packet_start(SSH2_MSG_USERAUTH_BANNER);
261 break; 390 packet_put_cstring(**prompts);
391 packet_put_cstring("");
392 packet_send();
393 packet_write_wait();
262#endif 394#endif
395 xfree(**prompts);
396 **prompts = NULL;
397 }
398 if (type == PAM_SUCCESS) {
399 *num = 0;
400 **echo_on = 0;
401 ctxt->pam_done = 1;
402 xfree(msg);
403 return (0);
404 }
405 error("PAM: %s", msg);
263 default: 406 default:
264 logit("PAM rejected by account configuration[%d]: " 407 *num = 0;
265 "%.200s", pam_retval, PAM_STRERROR(__pamh, 408 **echo_on = 0;
266 pam_retval)); 409 xfree(msg);
267 return(0); 410 ctxt->pam_done = -1;
411 return (-1);
412 }
268 } 413 }
269 414 return (-1);
270 return(1);
271} 415}
272 416
273/* Do PAM-specific session initialisation */ 417/* XXX - see also comment in auth-chall.c:verify_response */
274void do_pam_session(char *username, const char *ttyname) 418static int
419sshpam_respond(void *ctx, u_int num, char **resp)
275{ 420{
276 int pam_retval; 421 Buffer buffer;
277 422 struct pam_ctxt *ctxt = ctx;
278 do_pam_set_conv(&conv); 423
279 424 debug2("PAM: %s", __func__);
280 if (ttyname != NULL) { 425 switch (ctxt->pam_done) {
281 debug("PAM setting tty to \"%.200s\"", ttyname); 426 case 1:
282 pam_retval = pam_set_item(__pamh, PAM_TTY, ttyname); 427 sshpam_authenticated = 1;
283 if (pam_retval != PAM_SUCCESS) 428 return (0);
284 fatal("PAM set tty failed[%d]: %.200s", 429 case 0:
285 pam_retval, PAM_STRERROR(__pamh, pam_retval)); 430 break;
431 default:
432 return (-1);
286 } 433 }
287 434 if (num != 1) {
288 pam_retval = pam_open_session(__pamh, 0); 435 error("PAM: expected one response, got %u", num);
289 if (pam_retval != PAM_SUCCESS) 436 return (-1);
290 fatal("PAM session setup failed[%d]: %.200s", 437 }
291 pam_retval, PAM_STRERROR(__pamh, pam_retval)); 438 buffer_init(&buffer);
292 439 buffer_put_cstring(&buffer, *resp);
293 session_opened = 1; 440 ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer);
441 buffer_free(&buffer);
442 return (1);
294} 443}
295 444
296/* Set PAM credentials */ 445static void
297void do_pam_setcred(int init) 446sshpam_free_ctx(void *ctxtp)
298{ 447{
299 int pam_retval; 448 struct pam_ctxt *ctxt = ctxtp;
300
301 if (__pamh == NULL)
302 return;
303 449
304 do_pam_set_conv(&conv); 450 fatal_remove_cleanup(sshpam_thread_cleanup, ctxt);
305 451 sshpam_thread_cleanup(ctxtp);
306 debug("PAM establishing creds"); 452 xfree(ctxt);
307 pam_retval = pam_setcred(__pamh, 453 /*
308 init ? PAM_ESTABLISH_CRED : PAM_REINITIALIZE_CRED); 454 * We don't call sshpam_cleanup() here because we may need the PAM
309 if (pam_retval != PAM_SUCCESS) { 455 * handle at a later stage, e.g. when setting up a session. It's
310 if (was_authenticated) 456 * still on the cleanup list, so pam_end() *will* be called before
311 fatal("PAM setcred failed[%d]: %.200s", 457 * the server process terminates.
312 pam_retval, PAM_STRERROR(__pamh, pam_retval)); 458 */
313 else
314 debug("PAM setcred failed[%d]: %.200s",
315 pam_retval, PAM_STRERROR(__pamh, pam_retval));
316 } else
317 creds_set = 1;
318} 459}
319 460
320/* accessor function for file scope static variable */ 461KbdintDevice sshpam_device = {
321int is_pam_password_change_required(void) 462 "pam",
322{ 463 sshpam_init_ctx,
323 return password_change_required; 464 sshpam_query,
324} 465 sshpam_respond,
466 sshpam_free_ctx
467};
468
469KbdintDevice mm_sshpam_device = {
470 "pam",
471 mm_sshpam_init_ctx,
472 mm_sshpam_query,
473 mm_sshpam_respond,
474 mm_sshpam_free_ctx
475};
325 476
326/* 477/*
327 * Have user change authentication token if pam_acct_mgmt() indicated 478 * This replaces auth-pam.c
328 * it was expired. This needs to be called after an interactive
329 * session is established and the user's pty is connected to
330 * stdin/stdout/stderr.
331 */ 479 */
332void do_pam_chauthtok(void) 480void
481start_pam(const char *user)
333{ 482{
334 int pam_retval; 483 if (sshpam_init(user) == -1)
335 484 fatal("PAM: initialisation failed");
336 do_pam_set_conv(&conv);
337
338 if (password_change_required) {
339 if (use_privsep)
340 fatal("Password changing is currently unsupported"
341 " with privilege separation");
342 pamstate = OTHER;
343 pam_retval = pam_chauthtok(__pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
344 if (pam_retval != PAM_SUCCESS)
345 fatal("PAM pam_chauthtok failed[%d]: %.200s",
346 pam_retval, PAM_STRERROR(__pamh, pam_retval));
347#if 0
348 /* XXX: This would need to be done in the parent process,
349 * but there's currently no way to pass such request. */
350 no_port_forwarding_flag &= ~2;
351 no_agent_forwarding_flag &= ~2;
352 no_x11_forwarding_flag &= ~2;
353 if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
354 channel_permit_all_opens();
355#endif
356 }
357} 485}
358 486
359/* Cleanly shutdown PAM */ 487void
360void finish_pam(void) 488finish_pam(void)
361{ 489{
362 do_pam_cleanup_proc(NULL); 490 fatal_remove_cleanup(sshpam_cleanup, NULL);
363 fatal_remove_cleanup(&do_pam_cleanup_proc, NULL); 491 sshpam_cleanup(NULL);
364} 492}
365 493
366/* Start PAM authentication for specified account */ 494int
367void start_pam(const char *user) 495do_pam_account(const char *user, const char *ruser)
368{ 496{
369 int pam_retval; 497 /* XXX */
370 extern ServerOptions options; 498 return (1);
371 extern u_int utmp_len; 499}
372 const char *rhost;
373
374 debug("Starting up PAM with username \"%.200s\"", user);
375
376 pam_retval = pam_start(SSHD_PAM_SERVICE, user, &conv, &__pamh);
377
378 if (pam_retval != PAM_SUCCESS)
379 fatal("PAM initialisation failed[%d]: %.200s",
380 pam_retval, PAM_STRERROR(__pamh, pam_retval));
381
382 rhost = get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping);
383 debug("PAM setting rhost to \"%.200s\"", rhost);
384 500
385 pam_retval = pam_set_item(__pamh, PAM_RHOST, rhost); 501void
386 if (pam_retval != PAM_SUCCESS) 502do_pam_session(const char *user, const char *tty)
387 fatal("PAM set rhost failed[%d]: %.200s", pam_retval, 503{
388 PAM_STRERROR(__pamh, pam_retval)); 504 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
389#ifdef PAM_TTY_KLUDGE 505 (const void *)&null_conv);
390 /* 506 if (sshpam_err != PAM_SUCCESS)
391 * Some PAM modules (e.g. pam_time) require a TTY to operate, 507 fatal("PAM: failed to set PAM_CONV: %s",
392 * and will fail in various stupid ways if they don't get one. 508 pam_strerror(sshpam_handle, sshpam_err));
393 * sshd doesn't set the tty until too late in the auth process and may 509 debug("PAM: setting PAM_TTY to \"%s\"", tty);
394 * not even need one (for tty-less connections) 510 sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);
395 * Kludge: Set a fake PAM_TTY 511 if (sshpam_err != PAM_SUCCESS)
396 */ 512 fatal("PAM: failed to set PAM_TTY: %s",
397 pam_retval = pam_set_item(__pamh, PAM_TTY, "NODEVssh"); 513 pam_strerror(sshpam_handle, sshpam_err));
398 if (pam_retval != PAM_SUCCESS) 514 sshpam_err = pam_open_session(sshpam_handle, 0);
399 fatal("PAM set tty failed[%d]: %.200s", 515 if (sshpam_err != PAM_SUCCESS)
400 pam_retval, PAM_STRERROR(__pamh, pam_retval)); 516 fatal("PAM: pam_open_session(): %s",
401#endif /* PAM_TTY_KLUDGE */ 517 pam_strerror(sshpam_handle, sshpam_err));
518 sshpam_session_open = 1;
519}
402 520
403 fatal_add_cleanup(&do_pam_cleanup_proc, NULL); 521void
522do_pam_setcred(int init)
523{
524 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
525 (const void *)&null_conv);
526 if (sshpam_err != PAM_SUCCESS)
527 fatal("PAM: failed to set PAM_CONV: %s",
528 pam_strerror(sshpam_handle, sshpam_err));
529 if (init) {
530 debug("PAM: establishing credentials");
531 sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
532 } else {
533 debug("PAM: reinitializing credentials");
534 sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
535 }
536 if (sshpam_err == PAM_SUCCESS) {
537 sshpam_cred_established = 1;
538 return;
539 }
540 if (sshpam_authenticated)
541 fatal("PAM: pam_setcred(): %s",
542 pam_strerror(sshpam_handle, sshpam_err));
543 else
544 debug("PAM: pam_setcred(): %s",
545 pam_strerror(sshpam_handle, sshpam_err));
404} 546}
405 547
406/* Return list of PAM environment strings */ 548int
407char **fetch_pam_environment(void) 549is_pam_password_change_required(void)
408{ 550{
409#ifdef HAVE_PAM_GETENVLIST 551 return (sshpam_new_authtok_reqd);
410 return(pam_getenvlist(__pamh));
411#else /* HAVE_PAM_GETENVLIST */
412 return(NULL);
413#endif /* HAVE_PAM_GETENVLIST */
414} 552}
415 553
416void free_pam_environment(char **env) 554static int
555pam_chauthtok_conv(int n,
556 const struct pam_message **msg,
557 struct pam_response **resp,
558 void *data)
417{ 559{
560 char input[PAM_MAX_MSG_SIZE];
418 int i; 561 int i;
419 562
420 if (env != NULL) { 563 if (n <= 0 || n > PAM_MAX_NUM_MSG)
421 for (i = 0; env[i] != NULL; i++) 564 return (PAM_CONV_ERR);
422 xfree(env[i]); 565 *resp = xmalloc(n * sizeof **resp);
566 for (i = 0; i < n; ++i) {
567 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
568 case PAM_PROMPT_ECHO_OFF:
569 resp[i]->resp =
570 read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
571 RP_ALLOW_STDIN);
572 resp[i]->resp_retcode = PAM_SUCCESS;
573 break;
574 case PAM_PROMPT_ECHO_ON:
575 fputs(PAM_MSG_MEMBER(msg, i, msg), stderr);
576 fgets(input, sizeof input, stdin);
577 resp[i]->resp = xstrdup(input);
578 resp[i]->resp_retcode = PAM_SUCCESS;
579 break;
580 case PAM_ERROR_MSG:
581 case PAM_TEXT_INFO:
582 fputs(PAM_MSG_MEMBER(msg, i, msg), stderr);
583 resp[i]->resp_retcode = PAM_SUCCESS;
584 break;
585 default:
586 goto fail;
587 }
423 } 588 }
589 return (PAM_SUCCESS);
590 fail:
591 while (i)
592 xfree(resp[--i]);
593 xfree(*resp);
594 *resp = NULL;
595 return (PAM_CONV_ERR);
424} 596}
425 597
426/* Print any messages that have been generated during authentication */ 598/*
427/* or account checking to stderr */ 599 * XXX this should be done in the authentication phase, but ssh1 doesn't
428void print_pam_messages(void) 600 * support that
601 */
602void
603do_pam_chauthtok(void)
429{ 604{
430 if (__pam_msg != NULL) 605 struct pam_conv pam_conv = { pam_chauthtok_conv, NULL };
431 fputs(__pam_msg, stderr); 606
607 if (use_privsep)
608 fatal("PAM: chauthtok not supprted with privsep");
609 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
610 (const void *)&pam_conv);
611 if (sshpam_err != PAM_SUCCESS)
612 fatal("PAM: failed to set PAM_CONV: %s",
613 pam_strerror(sshpam_handle, sshpam_err));
614 debug("PAM: changing password");
615 sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
616 if (sshpam_err != PAM_SUCCESS)
617 fatal("PAM: pam_chauthtok(): %s",
618 pam_strerror(sshpam_handle, sshpam_err));
432} 619}
433 620
434/* Append a message to buffer */ 621void
435void message_cat(char **p, const char *a) 622print_pam_messages(void)
436{ 623{
437 char *cp; 624 /* XXX */
438 size_t new_len; 625}
439
440 new_len = strlen(a);
441 626
442 if (*p) { 627char **
443 size_t len = strlen(*p); 628fetch_pam_environment(void)
629{
630#ifdef HAVE_PAM_GETENVLIST
631 debug("PAM: retrieving environment");
632 return (pam_getenvlist(sshpam_handle));
633#else
634 return (NULL);
635#endif
636}
444 637
445 *p = xrealloc(*p, new_len + len + 2); 638void
446 cp = *p + len; 639free_pam_environment(char **env)
447 } else 640{
448 *p = cp = xmalloc(new_len + 2); 641 char **envp;
449 642
450 memcpy(cp, a, new_len); 643 for (envp = env; *envp; envp++)
451 cp[new_len] = '\n'; 644 xfree(*envp);
452 cp[new_len + 1] = '\0'; 645 xfree(env);
453} 646}
454 647
455#endif /* USE_PAM */ 648#endif /* USE_PAM */
diff --git a/auth-pam.h b/auth-pam.h
index 7881b6b80..5df65caa3 100644
--- a/auth-pam.h
+++ b/auth-pam.h
@@ -1,4 +1,4 @@
1/* $Id: auth-pam.h,v 1.16 2002/07/23 00:44:07 stevesk Exp $ */ 1/* $Id: auth-pam.h,v 1.17 2003/05/10 09:28:02 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000 Damien Miller. All rights reserved. 4 * Copyright (c) 2000 Damien Miller. All rights reserved.
@@ -37,8 +37,8 @@ int auth_pam_password(Authctxt *authctxt, const char *password);
37char **fetch_pam_environment(void); 37char **fetch_pam_environment(void);
38void free_pam_environment(char **env); 38void free_pam_environment(char **env);
39int do_pam_authenticate(int flags); 39int do_pam_authenticate(int flags);
40int do_pam_account(char *username, char *remote_user); 40int do_pam_account(const char *user, const char *ruser);
41void do_pam_session(char *username, const char *ttyname); 41void do_pam_session(const char *user, const char *tty);
42void do_pam_setcred(int init); 42void do_pam_setcred(int init);
43void print_pam_messages(void); 43void print_pam_messages(void);
44int is_pam_password_change_required(void); 44int is_pam_password_change_required(void);
diff --git a/auth-passwd.c b/auth-passwd.c
index 62ea3a52d..b893165bf 100644
--- a/auth-passwd.c
+++ b/auth-passwd.c
@@ -43,8 +43,8 @@ RCSID("$OpenBSD: auth-passwd.c,v 1.27 2002/05/24 16:45:16 stevesk Exp $");
43#include "servconf.h" 43#include "servconf.h"
44#include "auth.h" 44#include "auth.h"
45 45
46#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA) 46#if !defined(HAVE_OSF_SIA)
47/* Don't need any of these headers for the PAM or SIA cases */ 47/* Don't need any of these headers for the SIA cases */
48# ifdef HAVE_CRYPT_H 48# ifdef HAVE_CRYPT_H
49# include <crypt.h> 49# include <crypt.h>
50# endif 50# endif
@@ -78,7 +78,7 @@ RCSID("$OpenBSD: auth-passwd.c,v 1.27 2002/05/24 16:45:16 stevesk Exp $");
78# include <sys/cygwin.h> 78# include <sys/cygwin.h>
79# define is_winnt (GetVersion() < 0x80000000) 79# define is_winnt (GetVersion() < 0x80000000)
80# endif 80# endif
81#endif /* !USE_PAM && !HAVE_OSF_SIA */ 81#endif /* !HAVE_OSF_SIA */
82 82
83extern ServerOptions options; 83extern ServerOptions options;
84#ifdef WITH_AIXAUTHENTICATE 84#ifdef WITH_AIXAUTHENTICATE
@@ -94,7 +94,7 @@ auth_password(Authctxt *authctxt, const char *password)
94{ 94{
95 struct passwd * pw = authctxt->pw; 95 struct passwd * pw = authctxt->pw;
96 int ok = authctxt->valid; 96 int ok = authctxt->valid;
97#if !defined(USE_PAM) && !defined(HAVE_OSF_SIA) 97#if !defined(HAVE_OSF_SIA)
98 char *encrypted_password; 98 char *encrypted_password;
99 char *pw_password; 99 char *pw_password;
100 char *salt; 100 char *salt;
@@ -112,7 +112,7 @@ auth_password(Authctxt *authctxt, const char *password)
112 int authsuccess; 112 int authsuccess;
113 int reenter = 1; 113 int reenter = 1;
114# endif 114# endif
115#endif /* !defined(USE_PAM) && !defined(HAVE_OSF_SIA) */ 115#endif /* !defined(HAVE_OSF_SIA) */
116 116
117 /* deny if no user. */ 117 /* deny if no user. */
118 if (pw == NULL) 118 if (pw == NULL)
@@ -124,9 +124,7 @@ auth_password(Authctxt *authctxt, const char *password)
124 if (*password == '\0' && options.permit_empty_passwd == 0) 124 if (*password == '\0' && options.permit_empty_passwd == 0)
125 ok = 0; 125 ok = 0;
126 126
127#if defined(USE_PAM) 127#if defined(HAVE_OSF_SIA)
128 return auth_pam_password(authctxt, password) && ok;
129#elif defined(HAVE_OSF_SIA)
130 if (!ok) 128 if (!ok)
131 return 0; 129 return 0;
132 return auth_sia_password(authctxt, password); 130 return auth_sia_password(authctxt, password);
@@ -235,5 +233,5 @@ auth_password(Authctxt *authctxt, const char *password)
235 233
236 /* Authentication is accepted if the encrypted passwords are identical. */ 234 /* Authentication is accepted if the encrypted passwords are identical. */
237 return (strcmp(encrypted_password, pw_password) == 0); 235 return (strcmp(encrypted_password, pw_password) == 0);
238#endif /* !USE_PAM && !HAVE_OSF_SIA */ 236#endif /* !HAVE_OSF_SIA */
239} 237}
diff --git a/auth.h b/auth.h
index c75d75366..81d9655f7 100644
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,5 @@
1/* $OpenBSD: auth.h,v 1.41 2002/09/26 11:38:43 markus Exp $ */ 1/* $OpenBSD: auth.h,v 1.41 2002/09/26 11:38:43 markus Exp $ */
2/* $FreeBSD: src/crypto/openssh/auth.h,v 1.10 2003/03/31 13:45:36 des Exp $ */
2 3
3/* 4/*
4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 5 * Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -133,7 +134,6 @@ void krb5_cleanup_proc(void *authctxt);
133#endif /* KRB5 */ 134#endif /* KRB5 */
134 135
135#include "auth-pam.h" 136#include "auth-pam.h"
136#include "auth2-pam.h"
137 137
138Authctxt *do_authentication(void); 138Authctxt *do_authentication(void);
139Authctxt *do_authentication2(void); 139Authctxt *do_authentication2(void);
@@ -159,6 +159,7 @@ struct passwd * getpwnamallow(const char *user);
159 159
160char *get_challenge(Authctxt *); 160char *get_challenge(Authctxt *);
161int verify_response(Authctxt *, const char *); 161int verify_response(Authctxt *, const char *);
162void abandon_challenge_response(Authctxt *);
162 163
163struct passwd * auth_get_user(void); 164struct passwd * auth_get_user(void);
164 165
diff --git a/auth1.c b/auth1.c
index e7d744f6e..5086a47c3 100644
--- a/auth1.c
+++ b/auth1.c
@@ -73,7 +73,7 @@ do_authloop(Authctxt *authctxt)
73 char info[1024]; 73 char info[1024];
74 u_int dlen; 74 u_int dlen;
75 u_int ulen; 75 u_int ulen;
76 int type = 0; 76 int prev, type = 0;
77 struct passwd *pw = authctxt->pw; 77 struct passwd *pw = authctxt->pw;
78 78
79 debug("Attempting authentication for %s%.100s.", 79 debug("Attempting authentication for %s%.100s.",
@@ -103,8 +103,20 @@ do_authloop(Authctxt *authctxt)
103 info[0] = '\0'; 103 info[0] = '\0';
104 104
105 /* Get a packet from the client. */ 105 /* Get a packet from the client. */
106 prev = type;
106 type = packet_read(); 107 type = packet_read();
107 108
109 /*
110 * If we started challenge-response authentication but the
111 * next packet is not a response to our challenge, release
112 * the resources allocated by get_challenge() (which would
113 * normally have been released by verify_response() had we
114 * received such a response)
115 */
116 if (prev == SSH_CMSG_AUTH_TIS &&
117 type != SSH_CMSG_AUTH_TIS_RESPONSE)
118 abandon_challenge_response(authctxt);
119
108 /* Process the packet. */ 120 /* Process the packet. */
109 switch (type) { 121 switch (type) {
110 122
diff --git a/auth2-chall.c b/auth2-chall.c
index 0d1709307..12e3cc934 100644
--- a/auth2-chall.c
+++ b/auth2-chall.c
@@ -41,6 +41,9 @@ static void input_userauth_info_response(int, u_int32_t, void *);
41#ifdef BSD_AUTH 41#ifdef BSD_AUTH
42extern KbdintDevice bsdauth_device; 42extern KbdintDevice bsdauth_device;
43#else 43#else
44#ifdef USE_PAM
45extern KbdintDevice sshpam_device;
46#endif
44#ifdef SKEY 47#ifdef SKEY
45extern KbdintDevice skey_device; 48extern KbdintDevice skey_device;
46#endif 49#endif
@@ -50,6 +53,9 @@ KbdintDevice *devices[] = {
50#ifdef BSD_AUTH 53#ifdef BSD_AUTH
51 &bsdauth_device, 54 &bsdauth_device,
52#else 55#else
56#ifdef USE_PAM
57 &sshpam_device,
58#endif
53#ifdef SKEY 59#ifdef SKEY
54 &skey_device, 60 &skey_device,
55#endif 61#endif
@@ -323,15 +329,22 @@ privsep_challenge_enable(void)
323#ifdef BSD_AUTH 329#ifdef BSD_AUTH
324 extern KbdintDevice mm_bsdauth_device; 330 extern KbdintDevice mm_bsdauth_device;
325#endif 331#endif
332#ifdef USE_PAM
333 extern KbdintDevice mm_sshpam_device;
334#endif
326#ifdef SKEY 335#ifdef SKEY
327 extern KbdintDevice mm_skey_device; 336 extern KbdintDevice mm_skey_device;
328#endif 337#endif
329 /* As long as SSHv1 has devices[0] hard coded this is fine */ 338 int n = 0;
339
330#ifdef BSD_AUTH 340#ifdef BSD_AUTH
331 devices[0] = &mm_bsdauth_device; 341 devices[n++] = &mm_bsdauth_device;
332#else 342#else
343#ifdef USE_PAM
344 devices[n++] = &mm_sshpam_device;
345#endif
333#ifdef SKEY 346#ifdef SKEY
334 devices[0] = &mm_skey_device; 347 devices[n++] = &mm_skey_device;
335#endif 348#endif
336#endif 349#endif
337} 350}
diff --git a/auth2-kbdint.c b/auth2-kbdint.c
index e60992881..1696ef4d3 100644
--- a/auth2-kbdint.c
+++ b/auth2-kbdint.c
@@ -49,10 +49,6 @@ userauth_kbdint(Authctxt *authctxt)
49 if (options.challenge_response_authentication) 49 if (options.challenge_response_authentication)
50 authenticated = auth2_challenge(authctxt, devs); 50 authenticated = auth2_challenge(authctxt, devs);
51 51
52#ifdef USE_PAM
53 if (authenticated == 0 && options.pam_authentication_via_kbd_int)
54 authenticated = auth2_pam(authctxt);
55#endif
56 xfree(devs); 52 xfree(devs);
57 xfree(lang); 53 xfree(lang);
58#ifdef HAVE_CYGWIN 54#ifdef HAVE_CYGWIN
diff --git a/auth2-pam.c b/auth2-pam.c
deleted file mode 100644
index ac28fb245..000000000
--- a/auth2-pam.c
+++ /dev/null
@@ -1,165 +0,0 @@
1#include "includes.h"
2RCSID("$Id: auth2-pam.c,v 1.15 2003/01/08 01:37:03 djm Exp $");
3
4#ifdef USE_PAM
5#include <security/pam_appl.h>
6
7#include "ssh.h"
8#include "ssh2.h"
9#include "auth.h"
10#include "auth-pam.h"
11#include "packet.h"
12#include "xmalloc.h"
13#include "dispatch.h"
14#include "log.h"
15
16static int do_pam_conversation_kbd_int(int num_msg,
17 const struct pam_message **msg, struct pam_response **resp,
18 void *appdata_ptr);
19void input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt);
20
21struct {
22 int finished, num_received, num_expected;
23 int *prompts;
24 struct pam_response *responses;
25} context_pam2 = {0, 0, 0, NULL};
26
27static struct pam_conv conv2 = {
28 do_pam_conversation_kbd_int,
29 NULL,
30};
31
32int
33auth2_pam(Authctxt *authctxt)
34{
35 int retval = -1;
36
37 if (authctxt->user == NULL)
38 fatal("auth2_pam: internal error: no user");
39
40 conv2.appdata_ptr = authctxt;
41 do_pam_set_conv(&conv2);
42
43 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
44 &input_userauth_info_response_pam);
45 retval = (do_pam_authenticate(0) == PAM_SUCCESS);
46 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
47
48 return retval;
49}
50
51static int
52do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
53 struct pam_response **resp, void *appdata_ptr)
54{
55 int i, j, done;
56 char *text;
57
58 context_pam2.finished = 0;
59 context_pam2.num_received = 0;
60 context_pam2.num_expected = 0;
61 context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
62 context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
63 memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
64
65 text = NULL;
66 for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
67 int style = PAM_MSG_MEMBER(msg, i, msg_style);
68 switch (style) {
69 case PAM_PROMPT_ECHO_ON:
70 case PAM_PROMPT_ECHO_OFF:
71 context_pam2.num_expected++;
72 break;
73 case PAM_TEXT_INFO:
74 case PAM_ERROR_MSG:
75 default:
76 /* Capture all these messages to be sent at once */
77 message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
78 break;
79 }
80 }
81
82 if (context_pam2.num_expected == 0)
83 return PAM_SUCCESS;
84
85 packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
86 packet_put_cstring(""); /* Name */
87 packet_put_cstring(""); /* Instructions */
88 packet_put_cstring(""); /* Language */
89 packet_put_int(context_pam2.num_expected);
90
91 for (i = 0, j = 0; i < num_msg; i++) {
92 int style = PAM_MSG_MEMBER(msg, i, msg_style);
93
94 /* Skip messages which don't need a reply */
95 if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
96 continue;
97
98 context_pam2.prompts[j++] = i;
99 if (text) {
100 message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
101 packet_put_cstring(text);
102 text = NULL;
103 } else
104 packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
105 packet_put_char(style == PAM_PROMPT_ECHO_ON);
106 }
107 packet_send();
108 packet_write_wait();
109
110 /*
111 * Grabbing control of execution and spinning until we get what
112 * we want is probably rude, but it seems to work properly, and
113 * the client *should* be in lock-step with us, so the loop should
114 * only be traversed once.
115 */
116 while(context_pam2.finished == 0) {
117 done = 1;
118 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
119 if (context_pam2.finished == 0)
120 debug("extra packet during conversation");
121 }
122
123 if (context_pam2.num_received == context_pam2.num_expected) {
124 *resp = context_pam2.responses;
125 return PAM_SUCCESS;
126 } else
127 return PAM_CONV_ERR;
128}
129
130void
131input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt)
132{
133 Authctxt *authctxt = ctxt;
134 unsigned int nresp = 0, rlen = 0, i = 0;
135 char *resp;
136
137 if (authctxt == NULL)
138 fatal("input_userauth_info_response_pam: no authentication context");
139
140 nresp = packet_get_int(); /* Number of responses. */
141 debug("got %d responses", nresp);
142
143
144 if (nresp != context_pam2.num_expected)
145 fatal("%s: Received incorrect number of responses "
146 "(expected %d, received %u)", __func__,
147 context_pam2.num_expected, nresp);
148
149 if (nresp > 100)
150 fatal("%s: too many replies", __func__);
151
152 for (i = 0; i < nresp; i++) {
153 int j = context_pam2.prompts[i];
154
155 resp = packet_get_string(&rlen);
156 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
157 context_pam2.responses[j].resp = resp;
158 context_pam2.num_received++;
159 }
160
161 context_pam2.finished = 1;
162
163 packet_check_eom();
164}
165#endif
diff --git a/auth2-pam.h b/auth2-pam.h
deleted file mode 100644
index c54f811cf..000000000
--- a/auth2-pam.h
+++ /dev/null
@@ -1,8 +0,0 @@
1/* $Id: auth2-pam.h,v 1.2 2001/02/09 01:55:36 djm Exp $ */
2
3#include "includes.h"
4#ifdef USE_PAM
5
6int auth2_pam(Authctxt *authctxt);
7
8#endif /* USE_PAM */
diff --git a/configure.ac b/configure.ac
index dee852854..7a24838fe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
1# $Id: configure.ac,v 1.116 2003/05/10 07:05:46 dtucker Exp $ 1# $Id: configure.ac,v 1.117 2003/05/10 09:28:02 djm Exp $
2 2
3AC_INIT 3AC_INIT
4AC_CONFIG_SRCDIR([ssh.c]) 4AC_CONFIG_SRCDIR([ssh.c])
@@ -963,7 +963,7 @@ int main(void) { exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); }
963 963
964# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the 964# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the
965# version in OpenSSL. Skip this for PAM 965# version in OpenSSL. Skip this for PAM
966if test "x$PAM_MSG" = "xno" -a "x$check_for_libcrypt_later" = "x1"; then 966if test "x$check_for_libcrypt_later" = "x1"; then
967 AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt") 967 AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
968fi 968fi
969 969
diff --git a/monitor.c b/monitor.c
index 99b4d56ec..46241fbbd 100644
--- a/monitor.c
+++ b/monitor.c
@@ -118,6 +118,10 @@ int mm_answer_sessid(int, Buffer *);
118 118
119#ifdef USE_PAM 119#ifdef USE_PAM
120int mm_answer_pam_start(int, Buffer *); 120int mm_answer_pam_start(int, Buffer *);
121int mm_answer_pam_init_ctx(int, Buffer *);
122int mm_answer_pam_query(int, Buffer *);
123int mm_answer_pam_respond(int, Buffer *);
124int mm_answer_pam_free_ctx(int, Buffer *);
121#endif 125#endif
122 126
123#ifdef KRB4 127#ifdef KRB4
@@ -163,6 +167,10 @@ struct mon_table mon_dispatch_proto20[] = {
163 {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, 167 {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
164#ifdef USE_PAM 168#ifdef USE_PAM
165 {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, 169 {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
170 {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
171 {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
172 {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond},
173 {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx},
166#endif 174#endif
167#ifdef BSD_AUTH 175#ifdef BSD_AUTH
168 {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, 176 {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
@@ -205,6 +213,10 @@ struct mon_table mon_dispatch_proto15[] = {
205#endif 213#endif
206#ifdef USE_PAM 214#ifdef USE_PAM
207 {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, 215 {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
216 {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
217 {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
218 {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond},
219 {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx},
208#endif 220#endif
209#ifdef KRB4 221#ifdef KRB4
210 {MONITOR_REQ_KRB4, MON_ONCE|MON_AUTH, mm_answer_krb4}, 222 {MONITOR_REQ_KRB4, MON_ONCE|MON_AUTH, mm_answer_krb4},
@@ -285,10 +297,6 @@ monitor_child_preauth(struct monitor *pmonitor)
285 if (authctxt->pw->pw_uid == 0 && 297 if (authctxt->pw->pw_uid == 0 &&
286 !auth_root_allowed(auth_method)) 298 !auth_root_allowed(auth_method))
287 authenticated = 0; 299 authenticated = 0;
288#ifdef USE_PAM
289 if (!do_pam_account(authctxt->pw->pw_name, NULL))
290 authenticated = 0;
291#endif
292 } 300 }
293 301
294 if (ent->flags & MON_AUTHDECIDE) { 302 if (ent->flags & MON_AUTHDECIDE) {
@@ -747,6 +755,103 @@ mm_answer_pam_start(int socket, Buffer *m)
747 755
748 return (0); 756 return (0);
749} 757}
758
759static void *sshpam_ctxt, *sshpam_authok;
760extern KbdintDevice sshpam_device;
761
762int
763mm_answer_pam_init_ctx(int socket, Buffer *m)
764{
765
766 debug3("%s", __func__);
767 authctxt->user = buffer_get_string(m, NULL);
768 sshpam_ctxt = (sshpam_device.init_ctx)(authctxt);
769 sshpam_authok = NULL;
770 buffer_clear(m);
771 if (sshpam_ctxt != NULL) {
772 monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
773 buffer_put_int(m, 1);
774 } else {
775 buffer_put_int(m, 0);
776 }
777 mm_request_send(socket, MONITOR_ANS_PAM_INIT_CTX, m);
778 return (0);
779}
780
781int
782mm_answer_pam_query(int socket, Buffer *m)
783{
784 char *name, *info, **prompts;
785 u_int num, *echo_on;
786 int i, ret;
787
788 debug3("%s", __func__);
789 sshpam_authok = NULL;
790 ret = (sshpam_device.query)(sshpam_ctxt, &name, &info, &num, &prompts, &echo_on);
791 if (ret == 0 && num == 0)
792 sshpam_authok = sshpam_ctxt;
793 if (num > 1 || name == NULL || info == NULL)
794 ret = -1;
795 buffer_clear(m);
796 buffer_put_int(m, ret);
797 buffer_put_cstring(m, name);
798 xfree(name);
799 buffer_put_cstring(m, info);
800 xfree(info);
801 buffer_put_int(m, num);
802 for (i = 0; i < num; ++i) {
803 buffer_put_cstring(m, prompts[i]);
804 xfree(prompts[i]);
805 buffer_put_int(m, echo_on[i]);
806 }
807 if (prompts != NULL)
808 xfree(prompts);
809 if (echo_on != NULL)
810 xfree(echo_on);
811 mm_request_send(socket, MONITOR_ANS_PAM_QUERY, m);
812 return (0);
813}
814
815int
816mm_answer_pam_respond(int socket, Buffer *m)
817{
818 char **resp;
819 u_int num;
820 int i, ret;
821
822 debug3("%s", __func__);
823 sshpam_authok = NULL;
824 num = buffer_get_int(m);
825 if (num > 0) {
826 resp = xmalloc(num * sizeof(char *));
827 for (i = 0; i < num; ++i)
828 resp[i] = buffer_get_string(m, NULL);
829 ret = (sshpam_device.respond)(sshpam_ctxt, num, resp);
830 for (i = 0; i < num; ++i)
831 xfree(resp[i]);
832 xfree(resp);
833 } else {
834 ret = (sshpam_device.respond)(sshpam_ctxt, num, NULL);
835 }
836 buffer_clear(m);
837 buffer_put_int(m, ret);
838 mm_request_send(socket, MONITOR_ANS_PAM_RESPOND, m);
839 auth_method = "keyboard-interactive/pam";
840 if (ret == 0)
841 sshpam_authok = sshpam_ctxt;
842 return (0);
843}
844
845int
846mm_answer_pam_free_ctx(int socket, Buffer *m)
847{
848
849 debug3("%s", __func__);
850 (sshpam_device.free_ctx)(sshpam_ctxt);
851 buffer_clear(m);
852 mm_request_send(socket, MONITOR_ANS_PAM_FREE_CTX, m);
853 return (sshpam_authok == sshpam_ctxt);
854}
750#endif 855#endif
751 856
752static void 857static void
diff --git a/monitor.h b/monitor.h
index 668ac9897..3284ec5e6 100644
--- a/monitor.h
+++ b/monitor.h
@@ -1,4 +1,5 @@
1/* $OpenBSD: monitor.h,v 1.8 2002/09/26 11:38:43 markus Exp $ */ 1/* $OpenBSD: monitor.h,v 1.8 2002/09/26 11:38:43 markus Exp $ */
2/* $FreeBSD: src/crypto/openssh/monitor.h,v 1.3 2002/10/29 10:16:02 des Exp $ */
2 3
3/* 4/*
4 * Copyright 2002 Niels Provos <provos@citi.umich.edu> 5 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -52,6 +53,10 @@ enum monitor_reqtype {
52 MONITOR_REQ_KRB4, MONITOR_ANS_KRB4, 53 MONITOR_REQ_KRB4, MONITOR_ANS_KRB4,
53 MONITOR_REQ_KRB5, MONITOR_ANS_KRB5, 54 MONITOR_REQ_KRB5, MONITOR_ANS_KRB5,
54 MONITOR_REQ_PAM_START, 55 MONITOR_REQ_PAM_START,
56 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
57 MONITOR_REQ_PAM_QUERY, MONITOR_ANS_PAM_QUERY,
58 MONITOR_REQ_PAM_RESPOND, MONITOR_ANS_PAM_RESPOND,
59 MONITOR_REQ_PAM_FREE_CTX, MONITOR_ANS_PAM_FREE_CTX,
55 MONITOR_REQ_TERM 60 MONITOR_REQ_TERM
56}; 61};
57 62
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 183ae8d0e..a83413a5f 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -677,6 +677,88 @@ mm_start_pam(char *user)
677 677
678 buffer_free(&m); 678 buffer_free(&m);
679} 679}
680
681void *
682mm_sshpam_init_ctx(Authctxt *authctxt)
683{
684 Buffer m;
685 int success;
686
687 debug3("%s", __func__);
688 buffer_init(&m);
689 buffer_put_cstring(&m, authctxt->user);
690 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, &m);
691 debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__);
692 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_INIT_CTX, &m);
693 success = buffer_get_int(&m);
694 if (success == 0) {
695 debug3("%s: pam_init_ctx failed", __func__);
696 buffer_free(&m);
697 return (NULL);
698 }
699 buffer_free(&m);
700 return (authctxt);
701}
702
703int
704mm_sshpam_query(void *ctx, char **name, char **info,
705 u_int *num, char ***prompts, u_int **echo_on)
706{
707 Buffer m;
708 int i, ret;
709
710 debug3("%s", __func__);
711 buffer_init(&m);
712 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_QUERY, &m);
713 debug3("%s: waiting for MONITOR_ANS_PAM_QUERY", __func__);
714 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_QUERY, &m);
715 ret = buffer_get_int(&m);
716 debug3("%s: pam_query returned %d", __func__, ret);
717 *name = buffer_get_string(&m, NULL);
718 *info = buffer_get_string(&m, NULL);
719 *num = buffer_get_int(&m);
720 *prompts = xmalloc((*num + 1) * sizeof(char *));
721 *echo_on = xmalloc((*num + 1) * sizeof(u_int));
722 for (i = 0; i < *num; ++i) {
723 (*prompts)[i] = buffer_get_string(&m, NULL);
724 (*echo_on)[i] = buffer_get_int(&m);
725 }
726 buffer_free(&m);
727 return (ret);
728}
729
730int
731mm_sshpam_respond(void *ctx, u_int num, char **resp)
732{
733 Buffer m;
734 int i, ret;
735
736 debug3("%s", __func__);
737 buffer_init(&m);
738 buffer_put_int(&m, num);
739 for (i = 0; i < num; ++i)
740 buffer_put_cstring(&m, resp[i]);
741 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_RESPOND, &m);
742 debug3("%s: waiting for MONITOR_ANS_PAM_RESPOND", __func__);
743 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_RESPOND, &m);
744 ret = buffer_get_int(&m);
745 debug3("%s: pam_respond returned %d", __func__, ret);
746 buffer_free(&m);
747 return (ret);
748}
749
750void
751mm_sshpam_free_ctx(void *ctxtp)
752{
753 Buffer m;
754
755 debug3("%s", __func__);
756 buffer_init(&m);
757 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_FREE_CTX, &m);
758 debug3("%s: waiting for MONITOR_ANS_PAM_FREE_CTX", __func__);
759 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_FREE_CTX, &m);
760 buffer_free(&m);
761}
680#endif /* USE_PAM */ 762#endif /* USE_PAM */
681 763
682/* Request process termination */ 764/* Request process termination */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index d960a3d0b..f85bb2eda 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -1,4 +1,5 @@
1/* $OpenBSD: monitor_wrap.h,v 1.8 2002/09/26 11:38:43 markus Exp $ */ 1/* $OpenBSD: monitor_wrap.h,v 1.8 2002/09/26 11:38:43 markus Exp $ */
2/* $FreeBSD: src/crypto/openssh/monitor_wrap.h,v 1.3 2002/10/29 10:16:02 des Exp $ */
2 3
3/* 4/*
4 * Copyright 2002 Niels Provos <provos@citi.umich.edu> 5 * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -57,6 +58,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *);
57 58
58#ifdef USE_PAM 59#ifdef USE_PAM
59void mm_start_pam(char *); 60void mm_start_pam(char *);
61void *mm_sshpam_init_ctx(struct Authctxt *);
62int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **);
63int mm_sshpam_respond(void *, u_int, char **);
64void mm_sshpam_free_ctx(void *);
60#endif 65#endif
61 66
62void mm_terminate(void); 67void mm_terminate(void);