+/*
+ * Conversation function for authentication thread.
+ */
+static int
+sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
+ struct pam_response **resp, void *data)
+{
+ Buffer buffer;
+ struct pam_ctxt *ctxt;
+ struct pam_response *reply;
+ int i;
+
+ debug3("PAM: %s entering, %d messages", __func__, n);
+ *resp = NULL;
+
+ if (data == NULL) {
+ error("PAM: conversation function passed a null context");
+ return (PAM_CONV_ERR);
+ }
+ ctxt = data;
+ if (n <= 0 || n > PAM_MAX_NUM_MSG)
+ return (PAM_CONV_ERR);
+
+ if ((reply = malloc(n * sizeof(*reply))) == NULL)
+ return (PAM_CONV_ERR);
+ memset(reply, 0, n * sizeof(*reply));
+
+ buffer_init(&buffer);
+ for (i = 0; i < n; ++i) {
+ switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
+ case PAM_PROMPT_ECHO_OFF:
+ buffer_put_cstring(&buffer,
+ PAM_MSG_MEMBER(msg, i, msg));
+ if (ssh_msg_send(ctxt->pam_csock,
+ PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+ goto fail;
+ if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
+ goto fail;
+ if (buffer_get_char(&buffer) != PAM_AUTHTOK)
+ goto fail;
+ reply[i].resp = buffer_get_string(&buffer, NULL);
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ buffer_put_cstring(&buffer,
+ PAM_MSG_MEMBER(msg, i, msg));
+ if (ssh_msg_send(ctxt->pam_csock,
+ PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+ goto fail;
+ if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
+ goto fail;
+ if (buffer_get_char(&buffer) != PAM_AUTHTOK)
+ goto fail;
+ reply[i].resp = buffer_get_string(&buffer, NULL);
+ break;
+ case PAM_ERROR_MSG:
+ buffer_put_cstring(&buffer,
+ PAM_MSG_MEMBER(msg, i, msg));
+ if (ssh_msg_send(ctxt->pam_csock,
+ PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+ goto fail;
+ break;
+ case PAM_TEXT_INFO:
+ buffer_put_cstring(&buffer,
+ PAM_MSG_MEMBER(msg, i, msg));
+ if (ssh_msg_send(ctxt->pam_csock,
+ PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+ goto fail;
+ break;
+ default:
+ goto fail;
+ }
+ buffer_clear(&buffer);
+ }
+ buffer_free(&buffer);