t_openpam_readlinev.c revision 294192
1/*-
2 * Copyright (c) 2012 Dag-Erling Sm��rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Id: t_openpam_readlinev.c 648 2013-03-05 17:54:27Z des $
30 */
31
32#ifdef HAVE_CONFIG_H
33# include "config.h"
34#endif
35
36#include <err.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include <security/pam_appl.h>
42#include <security/openpam.h>
43
44#include "openpam_impl.h"
45#include "t.h"
46
47/*
48 * Read a line from the temp file and verify that the result matches our
49 * expectations: whether a line was read at all, how many and which words
50 * it contained, how many lines were read (in case of quoted or escaped
51 * newlines) and whether we reached the end of the file.
52 */
53static int
54orlv_expect(struct t_file *tf, const char **expectedv, int lines, int eof)
55{
56	int expectedc, gotc, i, lineno = 0;
57	char **gotv;
58
59	expectedc = 0;
60	if (expectedv != NULL)
61		while (expectedv[expectedc] != NULL)
62			++expectedc;
63	gotv = openpam_readlinev(tf->file, &lineno, &gotc);
64	if (t_ferror(tf))
65		err(1, "%s(): %s", __func__, tf->name);
66	if (expectedv != NULL && gotv == NULL) {
67		t_verbose("expected %d words, got nothing\n", expectedc);
68		return (0);
69	}
70	if (expectedv == NULL && gotv != NULL) {
71		t_verbose("expected nothing, got %d words\n", gotc);
72		FREEV(gotc, gotv);
73		return (0);
74	}
75	if (expectedv != NULL && gotv != NULL) {
76		if (expectedc != gotc) {
77			t_verbose("expected %d words, got %d\n",
78			    expectedc, gotc);
79			FREEV(gotc, gotv);
80			return (0);
81		}
82		for (i = 0; i < gotc; ++i) {
83			if (strcmp(expectedv[i], gotv[i]) != 0) {
84				t_verbose("word %d: expected <<%s>>, "
85				    "got <<%s>>\n", i, expectedv[i], gotv[i]);
86				FREEV(gotc, gotv);
87				return (0);
88			}
89		}
90		FREEV(gotc, gotv);
91	}
92	if (lineno != lines) {
93		t_verbose("expected to advance %d lines, advanced %d lines\n",
94		    lines, lineno);
95		return (0);
96	}
97	if (eof && !t_feof(tf)) {
98		t_verbose("expected EOF, but didn't get it\n");
99		return (0);
100	}
101	if (!eof && t_feof(tf)) {
102		t_verbose("didn't expect EOF, but got it anyway\n");
103		return (0);
104	}
105	return (1);
106}
107
108
109/***************************************************************************
110 * Commonly-used lines
111 */
112
113static const char *empty[] = {
114	NULL
115};
116
117static const char *hello[] = {
118	"hello",
119	NULL
120};
121
122static const char *hello_world[] = {
123	"hello",
124	"world",
125	NULL
126};
127
128
129/***************************************************************************
130 * Lines without words
131 */
132
133T_FUNC(empty_input, "empty input")
134{
135	struct t_file *tf;
136	int ret;
137
138	tf = t_fopen(NULL);
139	ret = orlv_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/);
140	t_fclose(tf);
141	return (ret);
142}
143
144T_FUNC(empty_line, "empty line")
145{
146	struct t_file *tf;
147	int ret;
148
149	tf = t_fopen(NULL);
150	t_fprintf(tf, "\n");
151	t_frewind(tf);
152	ret = orlv_expect(tf, empty, 1 /*lines*/, 0 /*eof*/);
153	t_fclose(tf);
154	return (ret);
155}
156
157T_FUNC(unterminated_empty_line, "unterminated empty line")
158{
159	struct t_file *tf;
160	int ret;
161
162	tf = t_fopen(NULL);
163	t_fprintf(tf, " ");
164	t_frewind(tf);
165	ret = orlv_expect(tf, NULL, 0 /*lines*/, 1 /*eof*/);
166	t_fclose(tf);
167	return (ret);
168}
169
170T_FUNC(whitespace, "whitespace")
171{
172	struct t_file *tf;
173	int ret;
174
175	tf = t_fopen(NULL);
176	t_fprintf(tf, " \n");
177	t_frewind(tf);
178	ret = orlv_expect(tf, empty, 1 /*lines*/, 0 /*eof*/);
179	t_fclose(tf);
180	return (ret);
181}
182
183T_FUNC(comment, "comment")
184{
185	struct t_file *tf;
186	int ret;
187
188	tf = t_fopen(NULL);
189	t_fprintf(tf, "# comment\n");
190	t_frewind(tf);
191	ret = orlv_expect(tf, empty, 1 /*lines*/, 0 /*eof*/);
192	t_fclose(tf);
193	return (ret);
194}
195
196T_FUNC(whitespace_before_comment, "whitespace before comment")
197{
198	struct t_file *tf;
199	int ret;
200
201	tf = t_fopen(NULL);
202	t_fprintf(tf, " # comment\n");
203	t_frewind(tf);
204	ret = orlv_expect(tf, empty, 1 /*lines*/, 0 /*eof*/);
205	t_fclose(tf);
206	return (ret);
207}
208
209
210/***************************************************************************
211 * Simple words
212 */
213
214T_FUNC(one_word, "one word")
215{
216	struct t_file *tf;
217	int ret;
218
219	tf = t_fopen(NULL);
220	t_fprintf(tf, "hello\n");
221	t_frewind(tf);
222	ret = orlv_expect(tf, hello, 1 /*lines*/, 0 /*eof*/);
223	t_fclose(tf);
224	return (ret);
225}
226
227T_FUNC(two_words, "two words")
228{
229	struct t_file *tf;
230	int ret;
231
232	tf = t_fopen(NULL);
233	t_fprintf(tf, "hello world\n");
234	t_frewind(tf);
235	ret = orlv_expect(tf, hello_world, 1 /*lines*/, 0 /*eof*/);
236	t_fclose(tf);
237	return (ret);
238}
239
240T_FUNC(unterminated_line, "unterminated line")
241{
242	struct t_file *tf;
243	int ret;
244
245	tf = t_fopen(NULL);
246	t_fprintf(tf, "hello world");
247	t_frewind(tf);
248	ret = orlv_expect(tf, hello_world, 0 /*lines*/, 1 /*eof*/);
249	t_fclose(tf);
250	return (ret);
251}
252
253
254/***************************************************************************
255 * Boilerplate
256 */
257
258static const struct t_test *t_plan[] = {
259	T(empty_input),
260	T(empty_line),
261	T(unterminated_empty_line),
262	T(whitespace),
263	T(comment),
264	T(whitespace_before_comment),
265
266	T(one_word),
267	T(two_words),
268	T(unterminated_line),
269
270	NULL
271};
272
273const struct t_test **
274t_prepare(int argc, char *argv[])
275{
276
277	(void)argc;
278	(void)argv;
279	return (t_plan);
280}
281
282void
283t_cleanup(void)
284{
285}
286