5 #include <security/pam_appl.h>
16 static int do_pam_conversation_kbd_int(int num_msg,
17 const struct pam_message **msg, struct pam_response **resp,
19 void input_userauth_info_response_pam(int type, int plen, void *ctxt);
22 int finished, num_received, num_expected;
24 struct pam_response *responses;
25 } context_pam2 = {0, 0, 0, NULL};
27 static struct pam_conv conv2 = {
28 do_pam_conversation_kbd_int,
33 auth2_pam(Authctxt *authctxt)
37 if (authctxt->user == NULL)
38 fatal("auth2_pam: internal error: no user");
40 conv2.appdata_ptr = authctxt;
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);
52 do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
53 struct pam_response **resp, void *appdata_ptr)
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);
66 for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
67 int style = PAM_MSG_MEMBER(msg, i, msg_style);
69 case PAM_PROMPT_ECHO_ON:
70 case PAM_PROMPT_ECHO_OFF:
71 context_pam2.num_expected++;
76 /* Capture all these messages to be sent at once */
77 message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
82 if (context_pam2.num_expected == 0)
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);
91 for (i = 0, j = 0; i < num_msg; i++) {
92 int style = PAM_MSG_MEMBER(msg, i, msg_style);
94 /* Skip messages which don't need a reply */
95 if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
98 context_pam2.prompts[j++] = i;
100 message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
101 packet_put_cstring(text);
104 packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
105 packet_put_char(style == PAM_PROMPT_ECHO_ON);
110 /* Grabbing control of execution and spinning until we get what
111 * we want is probably rude, but it seems to work properly, and
112 * the client *should* be in lock-step with us, so the loop should
113 * only be traversed once. */
114 while(context_pam2.finished == 0) {
116 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
117 if(context_pam2.finished == 0)
118 debug("extra packet during conversation");
121 if(context_pam2.num_received == context_pam2.num_expected) {
122 *resp = context_pam2.responses;
129 input_userauth_info_response_pam(int type, int plen, void *ctxt)
131 Authctxt *authctxt = ctxt;
132 unsigned int nresp = 0, rlen = 0, i = 0;
135 if (authctxt == NULL)
136 fatal("input_userauth_info_response_pam: no authentication context");
138 if (authctxt->attempt++ >= AUTH_FAIL_MAX)
139 packet_disconnect("too many failed userauth_requests");
141 nresp = packet_get_int(); /* Number of responses. */
142 debug("got %d responses", nresp);
144 for (i = 0; i < nresp; i++) {
145 int j = context_pam2.prompts[i];
147 resp = packet_get_string(&rlen);
148 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
149 context_pam2.responses[j].resp = xstrdup(resp);
151 context_pam2.num_received++;
154 context_pam2.finished = 1;