Esempio n. 1
0
int
my_conv(int n, const struct pam_message **msg,
    struct pam_response **resp, void *data)
{
	struct pam_response *aresp;
	char buf[PAM_MAX_RESP_SIZE];
	const char *p;
	int i;
	
	if (n <= 0 || n > PAM_MAX_NUM_MSG)
		return (PAM_CONV_ERR);
	
	if ((aresp = calloc(n, sizeof *aresp)) == NULL)
		return (PAM_BUF_ERR);
	
	for (i = 0; i < n; ++i) {
		aresp[i].resp_retcode = 0;
		aresp[i].resp = NULL;
		p = PAM_MSG_MEMBER(msg, i, msg);
		
		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
		case PAM_PROMPT_ECHO_OFF:
			aresp[i].resp = strdup(getpass(p));
			if (aresp[i].resp == NULL)
				goto fail;
			break;
		case PAM_PROMPT_ECHO_ON:
			fputs(p, stderr);
			if (fgets(buf, sizeof(buf), stdin) == NULL)
				goto fail;
			aresp[i].resp = strdup(buf);
			if (aresp[i].resp == NULL)
				goto fail;
			break;
		case PAM_ERROR_MSG:
			fputs(p, stderr);
			if (strlen(p) > 0 && p[strlen(p) - 1] != '\n')
				fputc('\n', stderr);
			break;
		case PAM_TEXT_INFO:
			fputs(p, stdout);
			if (strlen(p) > 0 && p[strlen(p) - 1] != '\n')
				fputc('\n', stdout);
			break;
		default:
			goto fail;
		}
	}
	*resp = aresp;
	return (PAM_SUCCESS);
fail:
	for (i = 0; i < n; ++i) {
		if (aresp[i].resp != NULL)
			free(aresp[i].resp);
	}
	*resp = NULL;
	return (PAM_CONV_ERR);
}
Esempio n. 2
0
static int
sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
    struct pam_response **resp, void *data)
{
	char input[PAM_MAX_MSG_SIZE];
	struct pam_response *reply;
	int i;

	debug3("PAM: %s called with %d messages", __func__, n);

	*resp = NULL;

	if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
		return (PAM_CONV_ERR);

	if ((reply = calloc(n, sizeof(*reply))) == NULL)
		return (PAM_CONV_ERR);

	for (i = 0; i < n; ++i) {
		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
		case PAM_PROMPT_ECHO_OFF:
			reply[i].resp =
			    read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
			    RP_ALLOW_STDIN);
			reply[i].resp_retcode = PAM_SUCCESS;
			break;
		case PAM_PROMPT_ECHO_ON:
			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
			if (fgets(input, sizeof input, stdin) == NULL)
				input[0] = '\0';
			if ((reply[i].resp = strdup(input)) == NULL)
				goto fail;
			reply[i].resp_retcode = PAM_SUCCESS;
			break;
		case PAM_ERROR_MSG:
		case PAM_TEXT_INFO:
			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
			reply[i].resp_retcode = PAM_SUCCESS;
			break;
		default:
			goto fail;
		}
	}
	*resp = reply;
	return (PAM_SUCCESS);

 fail:
	for(i = 0; i < n; i++) {
		if (reply[i].resp != NULL)
			xfree(reply[i].resp);
	}
	xfree(reply);
	return (PAM_CONV_ERR);
}
Esempio n. 3
0
/*
 * "Blind" conversation function for password authentication.  Assumes that
 * echo-off prompts are for the password and stores messages for later
 * display.
 */
static int
sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
    struct pam_response **resp, void *data)
{
	struct pam_response *reply;
	int i;
	size_t len;

	debug3("PAM: %s called with %d messages", __func__, n);

	*resp = NULL;

	if (n <= 0 || n > PAM_MAX_NUM_MSG)
		return (PAM_CONV_ERR);

	if ((reply = calloc(n, sizeof(*reply))) == NULL)
		return (PAM_CONV_ERR);

	for (i = 0; i < n; ++i) {
		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
		case PAM_PROMPT_ECHO_OFF:
			if (sshpam_password == NULL)
				goto fail;
			if ((reply[i].resp = strdup(sshpam_password)) == NULL)
				goto fail;
			reply[i].resp_retcode = PAM_SUCCESS;
			break;
		case PAM_ERROR_MSG:
		case PAM_TEXT_INFO:
			len = strlen(PAM_MSG_MEMBER(msg, i, msg));
			if (len > 0) {
				buffer_append(&loginmsg,
				    PAM_MSG_MEMBER(msg, i, msg), len);
				buffer_append(&loginmsg, "\n", 1);
			}
			if ((reply[i].resp = strdup("")) == NULL)
				goto fail;
			reply[i].resp_retcode = PAM_SUCCESS;
			break;
		default:
			goto fail;
		}
	}
	*resp = reply;
	return (PAM_SUCCESS);

 fail:
	for(i = 0; i < n; i++) {
		if (reply[i].resp != NULL)
			xfree(reply[i].resp);
	}
	xfree(reply);
	return (PAM_CONV_ERR);
}
Esempio n. 4
0
/*
 * PAM conversation function for non-interactive userauth methods that
 * really cannot do any prompting.  Password userauth and CHANGEREQ can
 * always set the PAM_AUTHTOK and PAM_OLDAUTHTOK items to avoid
 * conversation (and if they do and nonetheless some module tries to
 * converse, then password userauth / CHANGEREQ MUST fail).
 *
 * Except, PAM_TEXT_INFO and PAM_ERROR_MSG prompts can be squirelled
 * away and shown to the user later.
 *
 * Keyboard-interactive userauth has its own much more interesting
 * conversation function.
 *
 */
static int
do_pam_conversation(int num_msg, const struct pam_message **msg,
	struct pam_response **resp, void *appdata_ptr)
{
	struct pam_response *reply;
	int count;

	/* PAM will free this later */
	reply = xmalloc(num_msg * sizeof(*reply));

	(void) memset(reply, 0, num_msg * sizeof(*reply));

	for (count = 0; count < num_msg; count++) {
		/*
		 * We can't use stdio yet, queue messages for 
		 * printing later
		 */
		switch(PAM_MSG_MEMBER(msg, count, msg_style)) {
		case PAM_PROMPT_ECHO_ON:
			xfree(reply);
			return PAM_CONV_ERR;
		case PAM_PROMPT_ECHO_OFF:
			xfree(reply);
			return PAM_CONV_ERR;
			break;
		case PAM_ERROR_MSG:
		case PAM_TEXT_INFO:
			if (PAM_MSG_MEMBER(msg, count, msg) != NULL) {
				message_cat(&__pam_msg, 
				    PAM_MSG_MEMBER(msg, count, msg));
			}
			reply[count].resp = xstrdup("");
			reply[count].resp_retcode = PAM_SUCCESS;
			break;
		default:
			xfree(reply);
			return PAM_CONV_ERR;
		}
	}

	*resp = reply;

	return PAM_SUCCESS;
}
Esempio n. 5
0
static int
sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
    struct pam_response **resp, void *data)
{
	struct pam_response *reply;
	int r, i;

	debug3("PAM: %s called with %d messages", __func__, n);
	*resp = NULL;

	if (n <= 0 || n > PAM_MAX_NUM_MSG)
		return (PAM_CONV_ERR);

	if ((reply = calloc(n, sizeof(*reply))) == NULL)
		return (PAM_CONV_ERR);

	for (i = 0; i < n; ++i) {
		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
		case PAM_ERROR_MSG:
		case PAM_TEXT_INFO:
			if ((r = sshbuf_putf(loginmsg, "%s\n",
			    PAM_MSG_MEMBER(msg, i, msg))) != 0)
				fatal("%s: buffer error: %s",
				    __func__, ssh_err(r));
			reply[i].resp_retcode = PAM_SUCCESS;
			break;
		default:
			goto fail;
		}
	}
	*resp = reply;
	return (PAM_SUCCESS);

 fail:
	for(i = 0; i < n; i++) {
		free(reply[i].resp);
	}
	free(reply);
	return (PAM_CONV_ERR);
}
Esempio n. 6
0
/*
 * 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 = calloc(n, sizeof(*reply))) == NULL)
		return (PAM_CONV_ERR);

	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);
	*resp = reply;
	return (PAM_SUCCESS);

 fail:
	for(i = 0; i < n; i++) {
		free(reply[i].resp);
	}
	free(reply);
	buffer_free(&buffer);
	return (PAM_CONV_ERR);
}
static int
do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
    struct pam_response **resp, void *appdata_ptr)
{
	int i, j, done;
	char *text;

	context_pam2.finished = 0;
	context_pam2.num_received = 0;
	context_pam2.num_expected = 0;
	context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
	context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
	memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);

	text = NULL;
	for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
		int style = PAM_MSG_MEMBER(msg, i, msg_style);
		switch (style) {
		case PAM_PROMPT_ECHO_ON:
		case PAM_PROMPT_ECHO_OFF:
			context_pam2.num_expected++;
			break;
		case PAM_TEXT_INFO:
		case PAM_ERROR_MSG:
		default:
			/* Capture all these messages to be sent at once */
			message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
			break;
		}
	}

	if (context_pam2.num_expected == 0)
		return PAM_SUCCESS;

	packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
	packet_put_cstring("");	/* Name */
	packet_put_cstring("");	/* Instructions */
	packet_put_cstring("");	/* Language */
	packet_put_int(context_pam2.num_expected);
	
	for (i = 0, j = 0; i < num_msg; i++) {
		int style = PAM_MSG_MEMBER(msg, i, msg_style);
		
		/* Skip messages which don't need a reply */
		if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
			continue;
		
		context_pam2.prompts[j++] = i;
		if (text) {
			message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
			packet_put_cstring(text);
			text = NULL;
		} else
			packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
		packet_put_char(style == PAM_PROMPT_ECHO_ON);
	}
	packet_send();
	packet_write_wait();

	/*
	 * Grabbing control of execution and spinning until we get what
	 * we want is probably rude, but it seems to work properly, and
	 * the client *should* be in lock-step with us, so the loop should
	 * only be traversed once.
	 */
	while(context_pam2.finished == 0) {
		done = 1;
		dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
		if(context_pam2.finished == 0)
			debug("extra packet during conversation");
	}

	if(context_pam2.num_received == context_pam2.num_expected) {
		*resp = context_pam2.responses;
		return PAM_SUCCESS;
	} else
		return PAM_CONV_ERR;
}
Esempio n. 8
0
/*
 * Conversation function for authentication thread.
 */
static int
sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
    struct pam_response **resp, void *data)
{
	struct sshbuf *buffer;
	struct pam_ctxt *ctxt;
	struct pam_response *reply;
	int r, i;
	u_char status;

	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 = calloc(n, sizeof(*reply))) == NULL)
		return PAM_CONV_ERR;
	if ((buffer = sshbuf_new()) == NULL) {
		free(reply);
		return PAM_CONV_ERR;
	}

	for (i = 0; i < n; ++i) {
		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
		case PAM_PROMPT_ECHO_OFF:
		case PAM_PROMPT_ECHO_ON:
			if ((r = sshbuf_put_cstring(buffer,
			    PAM_MSG_MEMBER(msg, i, msg))) != 0)
				fatal("%s: buffer error: %s",
				    __func__, ssh_err(r));
			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 ((r = sshbuf_get_u8(buffer, &status)) != 0)
				fatal("%s: buffer error: %s",
				    __func__, ssh_err(r));
			if (status != PAM_AUTHTOK)
				goto fail;
			if ((r = sshbuf_get_cstring(buffer,
			    &reply[i].resp, NULL)) != 0)
				fatal("%s: buffer error: %s",
				    __func__, ssh_err(r));
			break;
		case PAM_ERROR_MSG:
		case PAM_TEXT_INFO:
			if ((r = sshbuf_put_cstring(buffer,
			    PAM_MSG_MEMBER(msg, i, msg))) != 0)
				fatal("%s: buffer error: %s",
				    __func__, ssh_err(r));
			if (ssh_msg_send(ctxt->pam_csock,
			    PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
				goto fail;
			break;
		default:
			goto fail;
		}
		sshbuf_reset(buffer);
	}
	sshbuf_free(buffer);
	*resp = reply;
	return (PAM_SUCCESS);

 fail:
	for(i = 0; i < n; i++) {
		free(reply[i].resp);
	}
	free(reply);
	sshbuf_free(buffer);
	return (PAM_CONV_ERR);
}