blob: c54ad31a28b98d60d4fff5581cc2ce0b26487fbb [file] [log] [blame]
Damien Millerb8481582000-12-03 11:51:51 +11001#include "includes.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +00002RCSID("$Id: auth2-pam.c,v 1.6 2001/01/22 05:34:40 mouring Exp $");
Damien Millerb8481582000-12-03 11:51:51 +11003
4#ifdef USE_PAM
Ben Lindstrom226cfa02001-01-22 05:34:40 +00005#include <security/pam_appl.h>
6
Damien Millerb8481582000-12-03 11:51:51 +11007#include "ssh.h"
8#include "ssh2.h"
9#include "auth.h"
10#include "packet.h"
11#include "xmalloc.h"
12#include "dispatch.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000013#include "log.h"
Damien Millerb8481582000-12-03 11:51:51 +110014
15struct {
16 int finished, num_received, num_expected;
17 int *prompts;
18 struct pam_response *responses;
19} context_pam2 = {0, 0, 0, NULL};
20
21static int do_conversation2(int num_msg, const struct pam_message **msg,
22 struct pam_response **resp, void *appdata_ptr);
23
24static struct pam_conv
25conv2 = {
26 do_conversation2,
27 NULL,
28};
29
30void input_userauth_info_response_pam(int type, int plen, void *ctxt);
31
32int
33auth2_pam(Authctxt *authctxt)
34{
35 int retval = -1;
Damien Millerb8481582000-12-03 11:51:51 +110036
37 if (authctxt->user == NULL)
38 fatal("auth2_pam: internal error: no user");
39
Damien Miller22e22bf2001-01-19 15:46:38 +110040 conv2.appdata_ptr = authctxt;
41 pam_set_conv(&conv2);
Damien Millerb8481582000-12-03 11:51:51 +110042
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
Damien Millerb8481582000-12-03 11:51:51 +110048 return retval;
49}
50
51static int
52do_conversation2(int num_msg, const struct pam_message **msg,
53 struct pam_response **resp, void *appdata_ptr)
54{
55 int echo = 0, i = 0, j = 0, done = 0;
56 char *tmp = NULL, *text = NULL;
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 packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
66 packet_put_cstring(""); /* Name */
67 packet_put_cstring(""); /* Instructions */
68 packet_put_cstring(""); /* Language */
69 for (i = 0, j = 0; i < num_msg; i++) {
Damien Miller82cf0ce2000-12-20 13:34:48 +110070 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
71 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
Damien Millerb8481582000-12-03 11:51:51 +110072 (i == num_msg - 1)) {
73 j++;
74 }
75 }
76 packet_put_int(j); /* Number of prompts. */
77 context_pam2.num_expected = j;
78 for (i = 0, j = 0; i < num_msg; i++) {
Damien Miller82cf0ce2000-12-20 13:34:48 +110079 switch(PAM_MSG_MEMBER(msg, i, msg_style)) {
Damien Millerb8481582000-12-03 11:51:51 +110080 case PAM_PROMPT_ECHO_ON:
81 echo = 1;
82 break;
83 case PAM_PROMPT_ECHO_OFF:
84 echo = 0;
85 break;
86 default:
87 echo = 0;
88 break;
89 }
90 if(text) {
Damien Miller82cf0ce2000-12-20 13:34:48 +110091 tmp = xmalloc(strlen(text) + strlen(PAM_MSG_MEMBER(msg, i, msg)) + 2);
Damien Millerb8481582000-12-03 11:51:51 +110092 strcpy(tmp, text);
93 strcat(tmp, "\n");
Damien Miller82cf0ce2000-12-20 13:34:48 +110094 strcat(tmp, PAM_MSG_MEMBER(msg, i, msg));
Damien Millerb8481582000-12-03 11:51:51 +110095 xfree(text);
96 text = tmp;
97 tmp = NULL;
98 } else {
Damien Miller82cf0ce2000-12-20 13:34:48 +110099 text = xstrdup(PAM_MSG_MEMBER(msg, i, msg));
Damien Millerb8481582000-12-03 11:51:51 +1100100 }
Damien Miller82cf0ce2000-12-20 13:34:48 +1100101 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
102 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
Damien Millerb8481582000-12-03 11:51:51 +1100103 (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);
108 packet_put_char(echo);
109 xfree(text);
110 text = NULL;
111 }
112 }
113 packet_send();
114 packet_write_wait();
115
116 /* Grabbing control of execution and spinning until we get what
117 * we want is probably rude, but it seems to work properly, and
118 * the client *should* be in lock-step with us, so the loop should
119 * only be traversed once. */
120 while(context_pam2.finished == 0) {
121 done = 1;
122 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
123 if(context_pam2.finished == 0) {
124 debug("extra packet during conversation");
125 }
126 }
127
128 if(context_pam2.num_received == context_pam2.num_expected) {
129 *resp = context_pam2.responses;
130 return PAM_SUCCESS;
131 } else {
132 return PAM_CONV_ERR;
133 }
134}
135
136void
137input_userauth_info_response_pam(int type, int plen, void *ctxt)
138{
139 Authctxt *authctxt = ctxt;
140 unsigned int nresp = 0, rlen = 0, i = 0;
141 char *resp;
142
143 if (authctxt == NULL)
144 fatal("input_userauth_info_response_pam: no authentication context");
145
146 if (authctxt->attempt++ >= AUTH_FAIL_MAX)
147 packet_disconnect("too many failed userauth_requests");
148
149 nresp = packet_get_int(); /* Number of responses. */
150 debug("got %d responses", nresp);
151
152 for (i = 0; i < nresp; i++) {
153 int j = context_pam2.prompts[i];
154 resp = packet_get_string(&rlen);
155 debug("response ssh-%d(pam-%d) = \"%s\"", i, j, resp);
156 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
157 context_pam2.responses[j].resp = xstrdup(resp);
158 xfree(resp);
159 context_pam2.num_received++;
160 }
161
162 context_pam2.finished = 1;
163
164 packet_done();
165}
166
167#endif