1313968Sdes/*-
2348980Sdes * Copyright (c) 2015-2017 Dag-Erling Sm��rgrav
3313968Sdes * All rights reserved.
4313968Sdes *
5313968Sdes * Redistribution and use in source and binary forms, with or without
6313968Sdes * modification, are permitted provided that the following conditions
7313968Sdes * are met:
8313968Sdes * 1. Redistributions of source code must retain the above copyright
9313968Sdes *    notice, this list of conditions and the following disclaimer.
10313968Sdes * 2. Redistributions in binary form must reproduce the above copyright
11313968Sdes *    notice, this list of conditions and the following disclaimer in the
12313968Sdes *    documentation and/or other materials provided with the distribution.
13313968Sdes * 3. The name of the author may not be used to endorse or promote
14313968Sdes *    products derived from this software without specific prior written
15313968Sdes *    permission.
16313968Sdes *
17313968Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18313968Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19313968Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20313968Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21313968Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22313968Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23313968Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24313968Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25313968Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26313968Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27313968Sdes * SUCH DAMAGE.
28313968Sdes *
29348980Sdes * $OpenPAM: t_pam_conv.c 938 2017-04-30 21:34:42Z des $
30313968Sdes */
31313968Sdes
32313968Sdes#ifdef HAVE_CONFIG_H
33313968Sdes# include "config.h"
34313968Sdes#endif
35313968Sdes
36313968Sdes#include <err.h>
37313968Sdes#include <errno.h>
38313968Sdes#include <stdint.h>
39313968Sdes#include <stdio.h>
40313968Sdes#include <stdlib.h>
41313968Sdes#include <string.h>
42313968Sdes
43313968Sdes#include <cryb/test.h>
44313968Sdes
45313968Sdes#include <security/pam_appl.h>
46313968Sdes#include <security/openpam.h>
47313968Sdes
48313968Sdes#include "openpam_impl.h"
49313968Sdes#include "openpam_asprintf.h"
50313968Sdes
51313968Sdes#include "t_pam_conv.h"
52313968Sdes
53313968Sdes/*
54313968Sdes * Conversation function
55313968Sdes *
56313968Sdes * The appdata argument points to a struct t_pam_conv_script which
57313968Sdes * contains both the expected messages and the desired responses.  If
58313968Sdes * script.responses is NULL, t_pam_conv() will return PAM_CONV_ERR.  If an
59313968Sdes * error occurs (incorrect number of messages, messages don't match script
60313968Sdes * etc.), script.comment will be set to point to a malloc()ed string
61313968Sdes * describing the error.  Otherwise, t_pam_conv() will return to its
62313968Sdes * caller a malloc()ed copy of script.responses.
63313968Sdes */
64313968Sdesint
65313968Sdest_pam_conv(int nm, const struct pam_message **msgs,
66313968Sdes    struct pam_response **respsp, void *ad)
67313968Sdes{
68313968Sdes	struct t_pam_conv_script *s = ad;
69313968Sdes	struct pam_response *resps;
70313968Sdes	int i;
71313968Sdes
72313968Sdes	/* check message count */
73313968Sdes	if (nm != s->nmsg) {
74313968Sdes		asprintf(&s->comment, "expected %d messages, got %d",
75313968Sdes		    s->nmsg, nm);
76313968Sdes		return (PAM_CONV_ERR);
77313968Sdes	}
78313968Sdes	if (nm <= 0 || nm > PAM_MAX_NUM_MSG) {
79313968Sdes		/* since the previous test passed, this is intentional! */
80313968Sdes		s->comment = NULL;
81313968Sdes		return (PAM_CONV_ERR);
82313968Sdes	}
83313968Sdes
84313968Sdes	/* check each message and provide the sed answer */
85313968Sdes	if ((resps = calloc(nm, sizeof *resps)) == NULL)
86313968Sdes		goto enomem;
87313968Sdes	for (i = 0; i < nm; ++i) {
88313968Sdes		if (msgs[i]->msg_style != s->msgs[i].msg_style) {
89313968Sdes			asprintf(&s->comment,
90313968Sdes			    "message %d expected style %d got %d", i,
91313968Sdes			    s->msgs[i].msg_style, msgs[i]->msg_style);
92313968Sdes			goto fail;
93313968Sdes		}
94313968Sdes		if (strcmp(msgs[i]->msg, s->msgs[i].msg) != 0) {
95313968Sdes			asprintf(&s->comment,
96313968Sdes			    "message %d expected \"%s\" got \"%s\"", i,
97313968Sdes			    s->msgs[i].msg, msgs[i]->msg);
98313968Sdes			goto fail;
99313968Sdes		}
100313968Sdes		switch (msgs[i]->msg_style) {
101313968Sdes		case PAM_PROMPT_ECHO_OFF:
102348980Sdes			t_printv("[PAM_PROMPT_ECHO_OFF] %s\n", msgs[i]->msg);
103313968Sdes			break;
104313968Sdes		case PAM_PROMPT_ECHO_ON:
105348980Sdes			t_printv("[PAM_PROMPT_ECHO_ON] %s\n", msgs[i]->msg);
106313968Sdes			break;
107313968Sdes		case PAM_ERROR_MSG:
108348980Sdes			t_printv("[PAM_ERROR_MSG] %s\n", msgs[i]->msg);
109313968Sdes			break;
110313968Sdes		case PAM_TEXT_INFO:
111348980Sdes			t_printv("[PAM_TEXT_INFO] %s\n", msgs[i]->msg);
112313968Sdes			break;
113313968Sdes		default:
114313968Sdes			asprintf(&s->comment, "invalid message style %d",
115313968Sdes			    msgs[i]->msg_style);
116313968Sdes			goto fail;
117313968Sdes		}
118313968Sdes		/* copy the response, if there is one */
119313968Sdes		if (s->resps[i].resp != NULL &&
120313968Sdes		    (resps[i].resp = strdup(s->resps[i].resp)) == NULL)
121313968Sdes			goto enomem;
122313968Sdes		resps[i].resp_retcode = s->resps[i].resp_retcode;
123313968Sdes	}
124313968Sdes	s->comment = NULL;
125313968Sdes	*respsp = resps;
126313968Sdes	return (PAM_SUCCESS);
127313968Sdesenomem:
128313968Sdes	asprintf(&s->comment, "%s", strerror(ENOMEM));
129313968Sdesfail:
130313968Sdes	for (i = 0; i < nm; ++i)
131313968Sdes		free(resps[i].resp);
132313968Sdes	free(resps);
133313968Sdes	return (PAM_CONV_ERR);
134313968Sdes}
135