blob: 498cc7461280c4667d094c5c0f935be4ef454030 [file] [log] [blame]
Damien Millerb8481582000-12-03 11:51:51 +11001#include "includes.h"
Ben Lindstromdb65e8f2001-01-19 04:26:52 +00002RCSID("$Id: auth2-pam.c,v 1.3 2001/01/19 04:26:52 mouring Exp $");
Damien Millerb8481582000-12-03 11:51:51 +11003
4#ifdef USE_PAM
5#include "ssh.h"
6#include "ssh2.h"
7#include "auth.h"
8#include "packet.h"
9#include "xmalloc.h"
10#include "dispatch.h"
11#include <security/pam_appl.h>
12
13struct {
14 int finished, num_received, num_expected;
15 int *prompts;
16 struct pam_response *responses;
17} context_pam2 = {0, 0, 0, NULL};
18
19static int do_conversation2(int num_msg, const struct pam_message **msg,
20 struct pam_response **resp, void *appdata_ptr);
21
22static struct pam_conv
23conv2 = {
24 do_conversation2,
25 NULL,
26};
27
28void input_userauth_info_response_pam(int type, int plen, void *ctxt);
29
30int
31auth2_pam(Authctxt *authctxt)
32{
33 int retval = -1;
34 char *method = "PAM";
35
36 if (authctxt->user == NULL)
37 fatal("auth2_pam: internal error: no user");
38
39 if (authctxt->valid) {
40 conv2.appdata_ptr = authctxt;
41 pam_set_conv(&conv2);
42 }
43
44 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
45 &input_userauth_info_response_pam);
46 retval = (do_pam_authenticate(0) == PAM_SUCCESS);
47 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
48
Ben Lindstromdb65e8f2001-01-19 04:26:52 +000049#if 0 /* ISSUE: No longer valid, but should this still be
50 handled?? */
Damien Millerb8481582000-12-03 11:51:51 +110051 userauth_log(authctxt, retval, method);
Ben Lindstromdb65e8f2001-01-19 04:26:52 +000052#endif
Damien Millerb8481582000-12-03 11:51:51 +110053 return retval;
54}
55
56static int
57do_conversation2(int num_msg, const struct pam_message **msg,
58 struct pam_response **resp, void *appdata_ptr)
59{
60 int echo = 0, i = 0, j = 0, done = 0;
61 char *tmp = NULL, *text = NULL;
62
63 context_pam2.finished = 0;
64 context_pam2.num_received = 0;
65 context_pam2.num_expected = 0;
66 context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
67 context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
68 memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
69
70 packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
71 packet_put_cstring(""); /* Name */
72 packet_put_cstring(""); /* Instructions */
73 packet_put_cstring(""); /* Language */
74 for (i = 0, j = 0; i < num_msg; i++) {
Damien Miller82cf0ce2000-12-20 13:34:48 +110075 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
76 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
Damien Millerb8481582000-12-03 11:51:51 +110077 (i == num_msg - 1)) {
78 j++;
79 }
80 }
81 packet_put_int(j); /* Number of prompts. */
82 context_pam2.num_expected = j;
83 for (i = 0, j = 0; i < num_msg; i++) {
Damien Miller82cf0ce2000-12-20 13:34:48 +110084 switch(PAM_MSG_MEMBER(msg, i, msg_style)) {
Damien Millerb8481582000-12-03 11:51:51 +110085 case PAM_PROMPT_ECHO_ON:
86 echo = 1;
87 break;
88 case PAM_PROMPT_ECHO_OFF:
89 echo = 0;
90 break;
91 default:
92 echo = 0;
93 break;
94 }
95 if(text) {
Damien Miller82cf0ce2000-12-20 13:34:48 +110096 tmp = xmalloc(strlen(text) + strlen(PAM_MSG_MEMBER(msg, i, msg)) + 2);
Damien Millerb8481582000-12-03 11:51:51 +110097 strcpy(tmp, text);
98 strcat(tmp, "\n");
Damien Miller82cf0ce2000-12-20 13:34:48 +110099 strcat(tmp, PAM_MSG_MEMBER(msg, i, msg));
Damien Millerb8481582000-12-03 11:51:51 +1100100 xfree(text);
101 text = tmp;
102 tmp = NULL;
103 } else {
Damien Miller82cf0ce2000-12-20 13:34:48 +1100104 text = xstrdup(PAM_MSG_MEMBER(msg, i, msg));
Damien Millerb8481582000-12-03 11:51:51 +1100105 }
Damien Miller82cf0ce2000-12-20 13:34:48 +1100106 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
107 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
Damien Millerb8481582000-12-03 11:51:51 +1100108 (i == num_msg - 1)) {
109 debug("sending prompt ssh-%d(pam-%d) = \"%s\"",
110 j, i, text);
111 context_pam2.prompts[j++] = i;
112 packet_put_cstring(text);
113 packet_put_char(echo);
114 xfree(text);
115 text = NULL;
116 }
117 }
118 packet_send();
119 packet_write_wait();
120
121 /* Grabbing control of execution and spinning until we get what
122 * we want is probably rude, but it seems to work properly, and
123 * the client *should* be in lock-step with us, so the loop should
124 * only be traversed once. */
125 while(context_pam2.finished == 0) {
126 done = 1;
127 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
128 if(context_pam2.finished == 0) {
129 debug("extra packet during conversation");
130 }
131 }
132
133 if(context_pam2.num_received == context_pam2.num_expected) {
134 *resp = context_pam2.responses;
135 return PAM_SUCCESS;
136 } else {
137 return PAM_CONV_ERR;
138 }
139}
140
141void
142input_userauth_info_response_pam(int type, int plen, void *ctxt)
143{
144 Authctxt *authctxt = ctxt;
145 unsigned int nresp = 0, rlen = 0, i = 0;
146 char *resp;
147
148 if (authctxt == NULL)
149 fatal("input_userauth_info_response_pam: no authentication context");
150
151 if (authctxt->attempt++ >= AUTH_FAIL_MAX)
152 packet_disconnect("too many failed userauth_requests");
153
154 nresp = packet_get_int(); /* Number of responses. */
155 debug("got %d responses", nresp);
156
157 for (i = 0; i < nresp; i++) {
158 int j = context_pam2.prompts[i];
159 resp = packet_get_string(&rlen);
160 debug("response ssh-%d(pam-%d) = \"%s\"", i, j, resp);
161 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
162 context_pam2.responses[j].resp = xstrdup(resp);
163 xfree(resp);
164 context_pam2.num_received++;
165 }
166
167 context_pam2.finished = 1;
168
169 packet_done();
170}
171
172#endif