summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2001-02-07 12:58:33 +1100
committerDamien Miller <djm@mindrot.org>2001-02-07 12:58:33 +1100
commit63dc3e90e5988d510c2bbddb46408f2e9220ec16 (patch)
tree1e04fafc0fc19d9388797ee4cbdc08a60f07d62f
parent582d3983d22c714588ca54bdd6c4b92aae450919 (diff)
- (djm) Much KNF on PAM code
- (djm) Revise auth-pam.c conversation function to be a little more readable. - (djm) Revise kbd-int PAM conversation function to fold all text messages to before first prompt. Fixes hangs if last pam_message did not require a reply. - (djm) Fix password changing when using PAM kbd-int authentication
-rw-r--r--ChangeLog6
-rw-r--r--auth-pam.c216
-rw-r--r--auth-pam.h1
-rw-r--r--auth2-pam.c113
4 files changed, 170 insertions, 166 deletions
diff --git a/ChangeLog b/ChangeLog
index 7f3d6922a..2fb64a5e0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
120010107 120010107
2 - (bal) Save the whole path to AR in configure. Some Solaris 2.7 installs 2 - (bal) Save the whole path to AR in configure. Some Solaris 2.7 installs
3 seem lose track of it while in openbsd-compat/ (two confirmed reports) 3 seem lose track of it while in openbsd-compat/ (two confirmed reports)
4 - (djm) Much KNF on PAM code
5 - (djm) Revise auth-pam.c conversation function to be a little more readable.
6 - (djm) Revise kbd-int PAM conversation function to fold all text messages
7 to before first prompt. Fixes hangs if last pam_message did not require
8 a reply.
9 - (djm) Fix password changing when using PAM kbd-int authentication
4 10
520010105 1120010105
6 - (bal) Disable groupaccess by setting NGROUPS_MAX to 0 for platforms 12 - (bal) Disable groupaccess by setting NGROUPS_MAX to 0 for platforms
diff --git a/auth-pam.c b/auth-pam.c
index ab985d15b..e6fddecc0 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -28,31 +28,29 @@
28#include "ssh.h" 28#include "ssh.h"
29#include "xmalloc.h" 29#include "xmalloc.h"
30#include "log.h" 30#include "log.h"
31#include "auth-pam.h"
31#include "servconf.h" 32#include "servconf.h"
32#include "canohost.h" 33#include "canohost.h"
33#include "readpass.h" 34#include "readpass.h"
34 35
35RCSID("$Id: auth-pam.c,v 1.24 2001/02/05 12:42:17 stevesk Exp $"); 36RCSID("$Id: auth-pam.c,v 1.25 2001/02/07 01:58:34 djm Exp $");
36 37
37#define NEW_AUTHTOK_MSG \ 38#define NEW_AUTHTOK_MSG \
38 "Warning: Your password has expired, please change it now" 39 "Warning: Your password has expired, please change it now"
39 40
40/* Callbacks */ 41static int do_pam_conversation(int num_msg, const struct pam_message **msg,
41static int pamconv(int num_msg, const struct pam_message **msg, 42 struct pam_response **resp, void *appdata_ptr);
42 struct pam_response **resp, void *appdata_ptr);
43void pam_cleanup_proc(void *context);
44void pam_msg_cat(const char *msg);
45 43
46/* module-local variables */ 44/* module-local variables */
47static struct pam_conv conv = { 45static struct pam_conv conv = {
48 pamconv, 46 do_pam_conversation,
49 NULL 47 NULL
50}; 48};
49static char *pam_msg = NULL;
51static pam_handle_t *pamh = NULL; 50static pam_handle_t *pamh = NULL;
52static const char *pampasswd = NULL; 51static const char *pampasswd = NULL;
53static char *pam_msg = NULL;
54 52
55/* states for pamconv() */ 53/* states for do_pam_conversation() */
56enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN; 54enum { INITIAL_LOGIN, OTHER } pamstate = INITIAL_LOGIN;
57/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */ 55/* remember whether pam_acct_mgmt() returned PAM_NEWAUTHTOK_REQD */
58static int password_change_required = 0; 56static int password_change_required = 0;
@@ -80,14 +78,14 @@ int do_pam_authenticate(int flags)
80 * 78 *
81 * INITIAL_LOGIN mode simply feeds the password from the client into 79 * INITIAL_LOGIN mode simply feeds the password from the client into
82 * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output 80 * PAM in response to PAM_PROMPT_ECHO_OFF, and collects output
83 * messages with pam_msg_cat(). This is used during initial 81 * messages with into pam_msg. This is used during initial
84 * authentication to bypass the normal PAM password prompt. 82 * authentication to bypass the normal PAM password prompt.
85 * 83 *
86 * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1) 84 * OTHER mode handles PAM_PROMPT_ECHO_OFF with read_passphrase(prompt, 1)
87 * and outputs messages to stderr. This mode is used if pam_chauthtok() 85 * and outputs messages to stderr. This mode is used if pam_chauthtok()
88 * is called to update expired passwords. 86 * is called to update expired passwords.
89 */ 87 */
90static int pamconv(int num_msg, const struct pam_message **msg, 88static int do_pam_conversation(int num_msg, const struct pam_message **msg,
91 struct pam_response **resp, void *appdata_ptr) 89 struct pam_response **resp, void *appdata_ptr)
92{ 90{
93 struct pam_response *reply; 91 struct pam_response *reply;
@@ -100,40 +98,28 @@ static int pamconv(int num_msg, const struct pam_message **msg,
100 return PAM_CONV_ERR; 98 return PAM_CONV_ERR;
101 99
102 for (count = 0; count < num_msg; count++) { 100 for (count = 0; count < num_msg; count++) {
103 switch(PAM_MSG_MEMBER(msg, count, msg_style)) { 101 if (pamstate == INITIAL_LOGIN) {
102 /*
103 * We can't use stdio yet, queue messages for
104 * printing later
105 */
106 switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
104 case PAM_PROMPT_ECHO_ON: 107 case PAM_PROMPT_ECHO_ON:
105 if (pamstate == INITIAL_LOGIN) { 108 free(reply);
109 return PAM_CONV_ERR;
110 case PAM_PROMPT_ECHO_OFF:
111 if (pampasswd == NULL) {
106 free(reply); 112 free(reply);
107 return PAM_CONV_ERR; 113 return PAM_CONV_ERR;
108 } else {
109 fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
110 fgets(buf, sizeof(buf), stdin);
111 reply[count].resp = xstrdup(buf);
112 reply[count].resp_retcode = PAM_SUCCESS;
113 break;
114 }
115 case PAM_PROMPT_ECHO_OFF:
116 if (pamstate == INITIAL_LOGIN) {
117 if (pampasswd == NULL) {
118 free(reply);
119 return PAM_CONV_ERR;
120 }
121 reply[count].resp = xstrdup(pampasswd);
122 } else {
123 reply[count].resp =
124 xstrdup(read_passphrase(PAM_MSG_MEMBER(msg, count, msg), 1));
125 } 114 }
115 reply[count].resp = xstrdup(pampasswd);
126 reply[count].resp_retcode = PAM_SUCCESS; 116 reply[count].resp_retcode = PAM_SUCCESS;
127 break; 117 break;
128 case PAM_ERROR_MSG: 118 case PAM_ERROR_MSG:
129 case PAM_TEXT_INFO: 119 case PAM_TEXT_INFO:
130 if ((*msg)[count].msg != NULL) { 120 if ((*msg)[count].msg != NULL) {
131 if (pamstate == INITIAL_LOGIN) 121 message_cat(&pam_msg,
132 pam_msg_cat(PAM_MSG_MEMBER(msg, count, msg)); 122 PAM_MSG_MEMBER(msg, count, msg));
133 else {
134 fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
135 fputs("\n", stderr);
136 }
137 } 123 }
138 reply[count].resp = xstrdup(""); 124 reply[count].resp = xstrdup("");
139 reply[count].resp_retcode = PAM_SUCCESS; 125 reply[count].resp_retcode = PAM_SUCCESS;
@@ -141,6 +127,36 @@ static int pamconv(int num_msg, const struct pam_message **msg,
141 default: 127 default:
142 free(reply); 128 free(reply);
143 return PAM_CONV_ERR; 129 return PAM_CONV_ERR;
130 }
131 } else {
132 /*
133 * stdio is connected, so interact directly
134 */
135 switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
136 case PAM_PROMPT_ECHO_ON:
137 fputs(PAM_MSG_MEMBER(msg, count, msg), stderr);
138 fgets(buf, sizeof(buf), stdin);
139 reply[count].resp = xstrdup(buf);
140 reply[count].resp_retcode = PAM_SUCCESS;
141 break;
142 case PAM_PROMPT_ECHO_OFF:
143 reply[count].resp = xstrdup(
144 read_passphrase(PAM_MSG_MEMBER(msg, count,
145 msg), 1));
146 reply[count].resp_retcode = PAM_SUCCESS;
147 break;
148 case PAM_ERROR_MSG:
149 case PAM_TEXT_INFO:
150 if ((*msg)[count].msg != NULL)
151 fprintf(stderr, "%s\n",
152 PAM_MSG_MEMBER(msg, count, msg));
153 reply[count].resp = xstrdup("");
154 reply[count].resp_retcode = PAM_SUCCESS;
155 break;
156 default:
157 free(reply);
158 return PAM_CONV_ERR;
159 }
144 } 160 }
145 } 161 }
146 162
@@ -154,25 +170,21 @@ void pam_cleanup_proc(void *context)
154{ 170{
155 int pam_retval; 171 int pam_retval;
156 172
157 if (pamh != NULL) 173 if (pamh) {
158 {
159 pam_retval = pam_close_session(pamh, 0); 174 pam_retval = pam_close_session(pamh, 0);
160 if (pam_retval != PAM_SUCCESS) { 175 if (pam_retval != PAM_SUCCESS)
161 log("Cannot close PAM session[%d]: %.200s", 176 log("Cannot close PAM session[%d]: %.200s",
162 pam_retval, PAM_STRERROR(pamh, pam_retval)); 177 pam_retval, PAM_STRERROR(pamh, pam_retval));
163 }
164 178
165 pam_retval = pam_setcred(pamh, PAM_DELETE_CRED); 179 pam_retval = pam_setcred(pamh, PAM_DELETE_CRED);
166 if (pam_retval != PAM_SUCCESS) { 180 if (pam_retval != PAM_SUCCESS)
167 debug("Cannot delete credentials[%d]: %.200s", 181 debug("Cannot delete credentials[%d]: %.200s",
168 pam_retval, PAM_STRERROR(pamh, pam_retval)); 182 pam_retval, PAM_STRERROR(pamh, pam_retval));
169 }
170 183
171 pam_retval = pam_end(pamh, pam_retval); 184 pam_retval = pam_end(pamh, pam_retval);
172 if (pam_retval != PAM_SUCCESS) { 185 if (pam_retval != PAM_SUCCESS)
173 log("Cannot release PAM authentication[%d]: %.200s", 186 log("Cannot release PAM authentication[%d]: %.200s",
174 pam_retval, PAM_STRERROR(pamh, pam_retval)); 187 pam_retval, PAM_STRERROR(pamh, pam_retval));
175 }
176 } 188 }
177} 189}
178 190
@@ -197,12 +209,13 @@ int auth_pam_password(struct passwd *pw, const char *password)
197 pamstate = INITIAL_LOGIN; 209 pamstate = INITIAL_LOGIN;
198 pam_retval = do_pam_authenticate(0); 210 pam_retval = do_pam_authenticate(0);
199 if (pam_retval == PAM_SUCCESS) { 211 if (pam_retval == PAM_SUCCESS) {
200 debug("PAM Password authentication accepted for user \"%.100s\"", 212 debug("PAM Password authentication accepted for "
201 pw->pw_name); 213 "user \"%.100s\"", pw->pw_name);
202 return 1; 214 return 1;
203 } else { 215 } else {
204 debug("PAM Password authentication for \"%.100s\" failed[%d]: %s", 216 debug("PAM Password authentication for \"%.100s\" "
205 pw->pw_name, pam_retval, PAM_STRERROR(pamh, pam_retval)); 217 "failed[%d]: %s", pw->pw_name, pam_retval,
218 PAM_STRERROR(pamh, pam_retval));
206 return 0; 219 return 0;
207 } 220 }
208} 221}
@@ -213,22 +226,21 @@ int do_pam_account(char *username, char *remote_user)
213 int pam_retval; 226 int pam_retval;
214 extern ServerOptions options; 227 extern ServerOptions options;
215 228
229 pam_set_conv(&conv);
230
216 debug("PAM setting rhost to \"%.200s\"", 231 debug("PAM setting rhost to \"%.200s\"",
217 get_canonical_hostname(options.reverse_mapping_check)); 232 get_canonical_hostname(options.reverse_mapping_check));
218 pam_retval = pam_set_item(pamh, PAM_RHOST, 233 pam_retval = pam_set_item(pamh, PAM_RHOST,
219 get_canonical_hostname(options.reverse_mapping_check)); 234 get_canonical_hostname(options.reverse_mapping_check));
220 if (pam_retval != PAM_SUCCESS) { 235 if (pam_retval != PAM_SUCCESS)
221 fatal("PAM set rhost failed[%d]: %.200s", 236 fatal("PAM set rhost failed[%d]: %.200s", pam_retval,
222 pam_retval, PAM_STRERROR(pamh, pam_retval)); 237 PAM_STRERROR(pamh, pam_retval));
223 } 238 if (remote_user) {
224
225 if (remote_user != NULL) {
226 debug("PAM setting ruser to \"%.200s\"", remote_user); 239 debug("PAM setting ruser to \"%.200s\"", remote_user);
227 pam_retval = pam_set_item(pamh, PAM_RUSER, remote_user); 240 pam_retval = pam_set_item(pamh, PAM_RUSER, remote_user);
228 if (pam_retval != PAM_SUCCESS) { 241 if (pam_retval != PAM_SUCCESS)
229 fatal("PAM set ruser failed[%d]: %.200s", 242 fatal("PAM set ruser failed[%d]: %.200s", pam_retval,
230 pam_retval, PAM_STRERROR(pamh, pam_retval)); 243 PAM_STRERROR(pamh, pam_retval));
231 }
232 } 244 }
233 245
234 pam_retval = pam_acct_mgmt(pamh, 0); 246 pam_retval = pam_acct_mgmt(pamh, 0);
@@ -237,13 +249,14 @@ int do_pam_account(char *username, char *remote_user)
237 /* This is what we want */ 249 /* This is what we want */
238 break; 250 break;
239 case PAM_NEW_AUTHTOK_REQD: 251 case PAM_NEW_AUTHTOK_REQD:
240 pam_msg_cat(NEW_AUTHTOK_MSG); 252 message_cat(&pam_msg, NEW_AUTHTOK_MSG);
241 /* flag that password change is necessary */ 253 /* flag that password change is necessary */
242 password_change_required = 1; 254 password_change_required = 1;
243 break; 255 break;
244 default: 256 default:
245 log("PAM rejected by account configuration[%d]: %.200s", 257 log("PAM rejected by account configuration[%d]: "
246 pam_retval, PAM_STRERROR(pamh, pam_retval)); 258 "%.200s", pam_retval, PAM_STRERROR(pamh,
259 pam_retval));
247 return(0); 260 return(0);
248 } 261 }
249 262
@@ -258,17 +271,15 @@ void do_pam_session(char *username, const char *ttyname)
258 if (ttyname != NULL) { 271 if (ttyname != NULL) {
259 debug("PAM setting tty to \"%.200s\"", ttyname); 272 debug("PAM setting tty to \"%.200s\"", ttyname);
260 pam_retval = pam_set_item(pamh, PAM_TTY, ttyname); 273 pam_retval = pam_set_item(pamh, PAM_TTY, ttyname);
261 if (pam_retval != PAM_SUCCESS) { 274 if (pam_retval != PAM_SUCCESS)
262 fatal("PAM set tty failed[%d]: %.200s", 275 fatal("PAM set tty failed[%d]: %.200s",
263 pam_retval, PAM_STRERROR(pamh, pam_retval)); 276 pam_retval, PAM_STRERROR(pamh, pam_retval));
264 }
265 } 277 }
266 278
267 pam_retval = pam_open_session(pamh, 0); 279 pam_retval = pam_open_session(pamh, 0);
268 if (pam_retval != PAM_SUCCESS) { 280 if (pam_retval != PAM_SUCCESS)
269 fatal("PAM session setup failed[%d]: %.200s", 281 fatal("PAM session setup failed[%d]: %.200s",
270 pam_retval, PAM_STRERROR(pamh, pam_retval)); 282 pam_retval, PAM_STRERROR(pamh, pam_retval));
271 }
272} 283}
273 284
274/* Set PAM credentials */ 285/* Set PAM credentials */
@@ -279,13 +290,12 @@ void do_pam_setcred(void)
279 debug("PAM establishing creds"); 290 debug("PAM establishing creds");
280 pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED); 291 pam_retval = pam_setcred(pamh, PAM_ESTABLISH_CRED);
281 if (pam_retval != PAM_SUCCESS) { 292 if (pam_retval != PAM_SUCCESS) {
282 if(was_authenticated) { 293 if (was_authenticated)
283 fatal("PAM setcred failed[%d]: %.200s", 294 fatal("PAM setcred failed[%d]: %.200s",
284 pam_retval, PAM_STRERROR(pamh, pam_retval)); 295 pam_retval, PAM_STRERROR(pamh, pam_retval));
285 } else { 296 else
286 debug("PAM setcred failed[%d]: %.200s", 297 debug("PAM setcred failed[%d]: %.200s",
287 pam_retval, PAM_STRERROR(pamh, pam_retval)); 298 pam_retval, PAM_STRERROR(pamh, pam_retval));
288 }
289 } 299 }
290} 300}
291 301
@@ -307,15 +317,13 @@ void do_pam_chauthtok(void)
307 317
308 if (password_change_required) { 318 if (password_change_required) {
309 pamstate = OTHER; 319 pamstate = OTHER;
310 /* 320 /* XXX: should we really loop forever? */
311 * XXX: should we really loop forever?
312 */
313 do { 321 do {
314 pam_retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 322 pam_retval = pam_chauthtok(pamh,
315 if (pam_retval != PAM_SUCCESS) { 323 PAM_CHANGE_EXPIRED_AUTHTOK);
324 if (pam_retval != PAM_SUCCESS)
316 log("PAM pam_chauthtok failed[%d]: %.200s", 325 log("PAM pam_chauthtok failed[%d]: %.200s",
317 pam_retval, PAM_STRERROR(pamh, pam_retval)); 326 pam_retval, PAM_STRERROR(pamh, pam_retval));
318 }
319 } while (pam_retval != PAM_SUCCESS); 327 } while (pam_retval != PAM_SUCCESS);
320 } 328 }
321} 329}
@@ -336,11 +344,9 @@ void start_pam(const char *user)
336 344
337 pam_retval = pam_start(SSHD_PAM_SERVICE, user, &conv, &pamh); 345 pam_retval = pam_start(SSHD_PAM_SERVICE, user, &conv, &pamh);
338 346
339 if (pam_retval != PAM_SUCCESS) { 347 if (pam_retval != PAM_SUCCESS)
340 fatal("PAM initialisation failed[%d]: %.200s", 348 fatal("PAM initialisation failed[%d]: %.200s",
341 pam_retval, PAM_STRERROR(pamh, pam_retval)); 349 pam_retval, PAM_STRERROR(pamh, pam_retval));
342 }
343
344#ifdef PAM_TTY_KLUDGE 350#ifdef PAM_TTY_KLUDGE
345 /* 351 /*
346 * Some PAM modules (e.g. pam_time) require a TTY to operate, 352 * Some PAM modules (e.g. pam_time) require a TTY to operate,
@@ -350,10 +356,9 @@ void start_pam(const char *user)
350 * Kludge: Set a fake PAM_TTY 356 * Kludge: Set a fake PAM_TTY
351 */ 357 */
352 pam_retval = pam_set_item(pamh, PAM_TTY, "ssh"); 358 pam_retval = pam_set_item(pamh, PAM_TTY, "ssh");
353 if (pam_retval != PAM_SUCCESS) { 359 if (pam_retval != PAM_SUCCESS)
354 fatal("PAM set tty failed[%d]: %.200s", 360 fatal("PAM set tty failed[%d]: %.200s",
355 pam_retval, PAM_STRERROR(pamh, pam_retval)); 361 pam_retval, PAM_STRERROR(pamh, pam_retval));
356 }
357#endif /* PAM_TTY_KLUDGE */ 362#endif /* PAM_TTY_KLUDGE */
358 363
359 fatal_add_cleanup(&pam_cleanup_proc, NULL); 364 fatal_add_cleanup(&pam_cleanup_proc, NULL);
@@ -377,26 +382,25 @@ void print_pam_messages(void)
377 fputs(pam_msg, stderr); 382 fputs(pam_msg, stderr);
378} 383}
379 384
380/* Append a message to the PAM message buffer */ 385/* Append a message to buffer */
381void pam_msg_cat(const char *msg) 386void message_cat(char **p, const char *a)
382{ 387{
383 char *p; 388 char *cp;
384 size_t new_msg_len; 389 size_t new_len;
385 size_t pam_msg_len;
386 390
387 new_msg_len = strlen(msg); 391 new_len = strlen(a);
388 392
389 if (pam_msg) { 393 if (*p) {
390 pam_msg_len = strlen(pam_msg); 394 size_t len = strlen(*p);
391 pam_msg = xrealloc(pam_msg, new_msg_len + pam_msg_len + 2); 395
392 p = pam_msg + pam_msg_len; 396 *p = xrealloc(*p, new_len + len + 2);
393 } else { 397 cp = *p + len;
394 pam_msg = p = xmalloc(new_msg_len + 2); 398 } else
395 } 399 *p = cp = xmalloc(new_len + 2);
396 400
397 memcpy(p, msg, new_msg_len); 401 memcpy(cp, a, new_len);
398 p[new_msg_len] = '\n'; 402 cp[new_len] = '\n';
399 p[new_msg_len + 1] = '\0'; 403 cp[new_len + 1] = '\0';
400} 404}
401 405
402#endif /* USE_PAM */ 406#endif /* USE_PAM */
diff --git a/auth-pam.h b/auth-pam.h
index 68d446592..8022493f0 100644
--- a/auth-pam.h
+++ b/auth-pam.h
@@ -15,5 +15,6 @@ void print_pam_messages(void);
15int pam_password_change_required(void); 15int pam_password_change_required(void);
16void do_pam_chauthtok(void); 16void do_pam_chauthtok(void);
17void pam_set_conv(struct pam_conv *); 17void pam_set_conv(struct pam_conv *);
18void message_cat(char **p, const char *a);
18 19
19#endif /* USE_PAM */ 20#endif /* USE_PAM */
diff --git a/auth2-pam.c b/auth2-pam.c
index d7a5ff7a4..24e0e0406 100644
--- a/auth2-pam.c
+++ b/auth2-pam.c
@@ -1,5 +1,5 @@
1#include "includes.h" 1#include "includes.h"
2RCSID("$Id: auth2-pam.c,v 1.7 2001/01/30 23:50:49 djm Exp $"); 2RCSID("$Id: auth2-pam.c,v 1.8 2001/02/07 01:58:33 djm Exp $");
3 3
4#ifdef USE_PAM 4#ifdef USE_PAM
5#include <security/pam_appl.h> 5#include <security/pam_appl.h>
@@ -7,28 +7,28 @@ RCSID("$Id: auth2-pam.c,v 1.7 2001/01/30 23:50:49 djm Exp $");
7#include "ssh.h" 7#include "ssh.h"
8#include "ssh2.h" 8#include "ssh2.h"
9#include "auth.h" 9#include "auth.h"
10#include "auth-pam.h"
10#include "packet.h" 11#include "packet.h"
11#include "xmalloc.h" 12#include "xmalloc.h"
12#include "dispatch.h" 13#include "dispatch.h"
13#include "log.h" 14#include "log.h"
14 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, int plen, void *ctxt);
20
15struct { 21struct {
16 int finished, num_received, num_expected; 22 int finished, num_received, num_expected;
17 int *prompts; 23 int *prompts;
18 struct pam_response *responses; 24 struct pam_response *responses;
19} context_pam2 = {0, 0, 0, NULL}; 25} context_pam2 = {0, 0, 0, NULL};
20 26
21static int do_conversation2(int num_msg, const struct pam_message **msg, 27static struct pam_conv conv2 = {
22 struct pam_response **resp, void *appdata_ptr); 28 do_pam_conversation_kbd_int,
23
24static struct pam_conv
25conv2 = {
26 do_conversation2,
27 NULL, 29 NULL,
28}; 30};
29 31
30void input_userauth_info_response_pam(int type, int plen, void *ctxt);
31
32int 32int
33auth2_pam(Authctxt *authctxt) 33auth2_pam(Authctxt *authctxt)
34{ 34{
@@ -41,7 +41,7 @@ auth2_pam(Authctxt *authctxt)
41 pam_set_conv(&conv2); 41 pam_set_conv(&conv2);
42 42
43 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, 43 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
44 &input_userauth_info_response_pam); 44 &input_userauth_info_response_pam);
45 retval = (do_pam_authenticate(0) == PAM_SUCCESS); 45 retval = (do_pam_authenticate(0) == PAM_SUCCESS);
46 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); 46 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
47 47
@@ -49,11 +49,11 @@ auth2_pam(Authctxt *authctxt)
49} 49}
50 50
51static int 51static int
52do_conversation2(int num_msg, const struct pam_message **msg, 52do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
53 struct pam_response **resp, void *appdata_ptr) 53 struct pam_response **resp, void *appdata_ptr)
54{ 54{
55 int echo = 0, i = 0, j = 0, done = 0; 55 int i, j, done;
56 char *tmp = NULL, *text = NULL; 56 char *text;
57 57
58 context_pam2.finished = 0; 58 context_pam2.finished = 0;
59 context_pam2.num_received = 0; 59 context_pam2.num_received = 0;
@@ -62,53 +62,47 @@ do_conversation2(int num_msg, const struct pam_message **msg,
62 context_pam2.responses = xmalloc(sizeof(struct pam_response) * 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); 63 memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
64 64
65 packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); 65 text = NULL;
66 packet_put_cstring(""); /* Name */ 66 for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
67 packet_put_cstring(""); /* Instructions */ 67 int style = PAM_MSG_MEMBER(msg, i, msg_style);
68 packet_put_cstring(""); /* Language */ 68 switch (style) {
69 for (i = 0, j = 0; i < num_msg; i++) { 69 case PAM_PROMPT_ECHO_ON:
70 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) || 70 case PAM_PROMPT_ECHO_OFF:
71 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) || 71 context_pam2.num_expected++;
72 (i == num_msg - 1)) { 72 break;
73 j++; 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;
74 } 79 }
75 } 80 }
76 packet_put_int(j); /* Number of prompts. */ 81
77 context_pam2.num_expected = j; 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
78 for (i = 0, j = 0; i < num_msg; i++) { 91 for (i = 0, j = 0; i < num_msg; i++) {
79 switch(PAM_MSG_MEMBER(msg, i, msg_style)) { 92 int style = PAM_MSG_MEMBER(msg, i, msg_style);
80 case PAM_PROMPT_ECHO_ON: 93
81 echo = 1; 94 /* Skip messages which don't need a reply */
82 break; 95 if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
83 case PAM_PROMPT_ECHO_OFF: 96 continue;
84 echo = 0; 97
85 break; 98 context_pam2.prompts[j++] = i;
86 default: 99 if (text) {
87 echo = 0; 100 message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
88 break;
89 }
90 if(text) {
91 tmp = xmalloc(strlen(text) + strlen(PAM_MSG_MEMBER(msg, i, msg)) + 2);
92 strcpy(tmp, text);
93 strcat(tmp, "\n");
94 strcat(tmp, PAM_MSG_MEMBER(msg, i, msg));
95 xfree(text);
96 text = tmp;
97 tmp = NULL;
98 } else {
99 text = xstrdup(PAM_MSG_MEMBER(msg, i, msg));
100 }
101 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
102 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
103 (i == num_msg - 1)) {
104 debug("sending prompt ssh-%d(pam-%d) = \"%s\"",
105 j, i, text);
106 context_pam2.prompts[j++] = i;
107 packet_put_cstring(text); 101 packet_put_cstring(text);
108 packet_put_char(echo);
109 xfree(text);
110 text = NULL; 102 text = NULL;
111 } 103 } else
104 packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
105 packet_put_char(style == PAM_PROMPT_ECHO_ON);
112 } 106 }
113 packet_send(); 107 packet_send();
114 packet_write_wait(); 108 packet_write_wait();
@@ -120,17 +114,15 @@ do_conversation2(int num_msg, const struct pam_message **msg,
120 while(context_pam2.finished == 0) { 114 while(context_pam2.finished == 0) {
121 done = 1; 115 done = 1;
122 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr); 116 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
123 if(context_pam2.finished == 0) { 117 if(context_pam2.finished == 0)
124 debug("extra packet during conversation"); 118 debug("extra packet during conversation");
125 }
126 } 119 }
127 120
128 if(context_pam2.num_received == context_pam2.num_expected) { 121 if(context_pam2.num_received == context_pam2.num_expected) {
129 *resp = context_pam2.responses; 122 *resp = context_pam2.responses;
130 return PAM_SUCCESS; 123 return PAM_SUCCESS;
131 } else { 124 } else
132 return PAM_CONV_ERR; 125 return PAM_CONV_ERR;
133 }
134} 126}
135 127
136void 128void
@@ -151,6 +143,7 @@ input_userauth_info_response_pam(int type, int plen, void *ctxt)
151 143
152 for (i = 0; i < nresp; i++) { 144 for (i = 0; i < nresp; i++) {
153 int j = context_pam2.prompts[i]; 145 int j = context_pam2.prompts[i];
146
154 resp = packet_get_string(&rlen); 147 resp = packet_get_string(&rlen);
155 context_pam2.responses[j].resp_retcode = PAM_SUCCESS; 148 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
156 context_pam2.responses[j].resp = xstrdup(resp); 149 context_pam2.responses[j].resp = xstrdup(resp);