11 #include <security/pam_appl.h>
14 int finished, num_received, num_expected;
16 struct pam_response *responses;
17 } context_pam2 = {0, 0, 0, NULL};
19 static int do_conversation2(int num_msg, const struct pam_message **msg,
20 struct pam_response **resp, void *appdata_ptr);
22 static struct pam_conv
28 void input_userauth_info_response_pam(int type, int plen, void *ctxt);
31 auth2_pam(Authctxt *authctxt)
36 if (authctxt->user == NULL)
37 fatal("auth2_pam: internal error: no user");
39 if (authctxt->valid) {
40 conv2.appdata_ptr = authctxt;
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);
49 userauth_log(authctxt, retval, method);
55 do_conversation2(int num_msg, const struct pam_message **msg,
56 struct pam_response **resp, void *appdata_ptr)
58 int echo = 0, i = 0, j = 0, done = 0;
59 char *tmp = NULL, *text = NULL;
61 context_pam2.finished = 0;
62 context_pam2.num_received = 0;
63 context_pam2.num_expected = 0;
64 context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
65 context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
66 memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
68 packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
69 packet_put_cstring(""); /* Name */
70 packet_put_cstring(""); /* Instructions */
71 packet_put_cstring(""); /* Language */
72 for (i = 0, j = 0; i < num_msg; i++) {
73 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
74 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
79 packet_put_int(j); /* Number of prompts. */
80 context_pam2.num_expected = j;
81 for (i = 0, j = 0; i < num_msg; i++) {
82 switch(PAM_MSG_MEMBER(msg, i, msg_style)) {
83 case PAM_PROMPT_ECHO_ON:
86 case PAM_PROMPT_ECHO_OFF:
94 tmp = xmalloc(strlen(text) + strlen(PAM_MSG_MEMBER(msg, i, msg)) + 2);
97 strcat(tmp, PAM_MSG_MEMBER(msg, i, msg));
102 text = xstrdup(PAM_MSG_MEMBER(msg, i, msg));
104 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
105 (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
106 (i == num_msg - 1)) {
107 debug("sending prompt ssh-%d(pam-%d) = \"%s\"",
109 context_pam2.prompts[j++] = i;
110 packet_put_cstring(text);
111 packet_put_char(echo);
119 /* Grabbing control of execution and spinning until we get what
120 * we want is probably rude, but it seems to work properly, and
121 * the client *should* be in lock-step with us, so the loop should
122 * only be traversed once. */
123 while(context_pam2.finished == 0) {
125 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
126 if(context_pam2.finished == 0) {
127 debug("extra packet during conversation");
131 if(context_pam2.num_received == context_pam2.num_expected) {
132 *resp = context_pam2.responses;
140 input_userauth_info_response_pam(int type, int plen, void *ctxt)
142 Authctxt *authctxt = ctxt;
143 unsigned int nresp = 0, rlen = 0, i = 0;
146 if (authctxt == NULL)
147 fatal("input_userauth_info_response_pam: no authentication context");
149 if (authctxt->attempt++ >= AUTH_FAIL_MAX)
150 packet_disconnect("too many failed userauth_requests");
152 nresp = packet_get_int(); /* Number of responses. */
153 debug("got %d responses", nresp);
155 for (i = 0; i < nresp; i++) {
156 int j = context_pam2.prompts[i];
157 resp = packet_get_string(&rlen);
158 debug("response ssh-%d(pam-%d) = \"%s\"", i, j, resp);
159 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
160 context_pam2.responses[j].resp = xstrdup(resp);
162 context_pam2.num_received++;
165 context_pam2.finished = 1;