t_openpam_readlinev.c revision 236099
1236099Sdes/*- 2236099Sdes * Copyright (c) 2012 Dag-Erling Sm��rgrav 3236099Sdes * All rights reserved. 4236099Sdes * 5236099Sdes * Redistribution and use in source and binary forms, with or without 6236099Sdes * modification, are permitted provided that the following conditions 7236099Sdes * are met: 8236099Sdes * 1. Redistributions of source code must retain the above copyright 9236099Sdes * notice, this list of conditions and the following disclaimer 10236099Sdes * in this position and unchanged. 11236099Sdes * 2. Redistributions in binary form must reproduce the above copyright 12236099Sdes * notice, this list of conditions and the following disclaimer in the 13236099Sdes * documentation and/or other materials provided with the distribution. 14236099Sdes * 3. The name of the author may not be used to endorse or promote 15236099Sdes * products derived from this software without specific prior written 16236099Sdes * permission. 17236099Sdes * 18236099Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19236099Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20236099Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21236099Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22236099Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23236099Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24236099Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25236099Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26236099Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27236099Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28236099Sdes * SUCH DAMAGE. 29236099Sdes * 30236099Sdes * $Id: t_openpam_readlinev.c 581 2012-04-06 01:08:37Z des $ 31236099Sdes */ 32236099Sdes 33236099Sdes#ifdef HAVE_CONFIG_H 34236099Sdes# include "config.h" 35236099Sdes#endif 36236099Sdes 37236099Sdes#include <err.h> 38236099Sdes#include <errno.h> 39236099Sdes#include <fcntl.h> 40236099Sdes#include <stdio.h> 41236099Sdes#include <stdlib.h> 42236099Sdes#include <string.h> 43236099Sdes#include <unistd.h> 44236099Sdes 45236099Sdes#include <security/pam_appl.h> 46236099Sdes#include <security/openpam.h> 47236099Sdes 48236099Sdes#include "openpam_impl.h" 49236099Sdes#include "t.h" 50236099Sdes 51236099Sdesstatic char filename[1024]; 52236099Sdesstatic FILE *f; 53236099Sdes 54236099Sdes/* 55236099Sdes * Open the temp file and immediately unlink it so it doesn't leak in case 56236099Sdes * of premature exit. 57236099Sdes */ 58236099Sdesstatic void 59236099Sdesorlv_open(void) 60236099Sdes{ 61236099Sdes int fd; 62236099Sdes 63236099Sdes if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) 64236099Sdes err(1, "%s(): %s", __func__, filename); 65236099Sdes if ((f = fdopen(fd, "r+")) == NULL) 66236099Sdes err(1, "%s(): %s", __func__, filename); 67236099Sdes if (unlink(filename) < 0) 68236099Sdes err(1, "%s(): %s", __func__, filename); 69236099Sdes} 70236099Sdes 71236099Sdes/* 72236099Sdes * Write text to the temp file. 73236099Sdes */ 74236099Sdesstatic void 75236099Sdesorlv_output(const char *fmt, ...) 76236099Sdes{ 77236099Sdes va_list ap; 78236099Sdes 79236099Sdes va_start(ap, fmt); 80236099Sdes vfprintf(f, fmt, ap); 81236099Sdes va_end(ap); 82236099Sdes if (ferror(f)) 83236099Sdes err(1, "%s", filename); 84236099Sdes} 85236099Sdes 86236099Sdes/* 87236099Sdes * Rewind the temp file. 88236099Sdes */ 89236099Sdesstatic void 90236099Sdesorlv_rewind(void) 91236099Sdes{ 92236099Sdes 93236099Sdes errno = 0; 94236099Sdes rewind(f); 95236099Sdes if (errno != 0) 96236099Sdes err(1, "%s(): %s", __func__, filename); 97236099Sdes} 98236099Sdes 99236099Sdes/* 100236099Sdes * Read a line from the temp file and verify that the result matches our 101236099Sdes * expectations: whether a line was read at all, how many and which words 102236099Sdes * it contained, how many lines were read (in case of quoted or escaped 103236099Sdes * newlines) and whether we reached the end of the file. 104236099Sdes */ 105236099Sdesstatic int 106236099Sdesorlv_expect(const char **expectedv, int lines, int eof) 107236099Sdes{ 108236099Sdes int expectedc, gotc, i, lineno = 0; 109236099Sdes char **gotv; 110236099Sdes 111236099Sdes expectedc = 0; 112236099Sdes if (expectedv != NULL) 113236099Sdes while (expectedv[expectedc] != NULL) 114236099Sdes ++expectedc; 115236099Sdes gotv = openpam_readlinev(f, &lineno, &gotc); 116236099Sdes if (ferror(f)) 117236099Sdes err(1, "%s(): %s", __func__, filename); 118236099Sdes if (expectedv != NULL && gotv == NULL) { 119236099Sdes t_verbose("expected %d words, got nothing\n", expectedc); 120236099Sdes return (0); 121236099Sdes } 122236099Sdes if (expectedv == NULL && gotv != NULL) { 123236099Sdes t_verbose("expected nothing, got %d words\n", gotc); 124236099Sdes FREEV(gotc, gotv); 125236099Sdes return (0); 126236099Sdes } 127236099Sdes if (expectedv != NULL && gotv != NULL) { 128236099Sdes if (expectedc != gotc) { 129236099Sdes t_verbose("expected %d words, got %d\n", 130236099Sdes expectedc, gotc); 131236099Sdes FREEV(gotc, gotv); 132236099Sdes return (0); 133236099Sdes } 134236099Sdes for (i = 0; i < gotc; ++i) { 135236099Sdes if (strcmp(expectedv[i], gotv[i]) != 0) { 136236099Sdes t_verbose("word %d: expected <<%s>>, " 137236099Sdes "got <<%s>>\n", i, expectedv[i], gotv[i]); 138236099Sdes FREEV(gotc, gotv); 139236099Sdes return (0); 140236099Sdes } 141236099Sdes } 142236099Sdes FREEV(gotc, gotv); 143236099Sdes } 144236099Sdes if (lineno != lines) { 145236099Sdes t_verbose("expected to advance %d lines, advanced %d lines\n", 146236099Sdes lines, lineno); 147236099Sdes return (0); 148236099Sdes } 149236099Sdes if (eof && !feof(f)) { 150236099Sdes t_verbose("expected EOF, but didn't get it\n"); 151236099Sdes return (0); 152236099Sdes } 153236099Sdes if (!eof && feof(f)) { 154236099Sdes t_verbose("didn't expect EOF, but got it anyway\n"); 155236099Sdes return (0); 156236099Sdes } 157236099Sdes return (1); 158236099Sdes} 159236099Sdes 160236099Sdes/* 161236099Sdes * Close the temp file. 162236099Sdes */ 163236099Sdesvoid 164236099Sdesorlv_close(void) 165236099Sdes{ 166236099Sdes 167236099Sdes if (fclose(f) != 0) 168236099Sdes err(1, "%s(): %s", __func__, filename); 169236099Sdes f = NULL; 170236099Sdes} 171236099Sdes 172236099Sdes/*************************************************************************** 173236099Sdes * Commonly-used lines 174236099Sdes */ 175236099Sdes 176236099Sdesstatic const char *empty[] = { 177236099Sdes NULL 178236099Sdes}; 179236099Sdes 180236099Sdesstatic const char *hello[] = { 181236099Sdes "hello", 182236099Sdes NULL 183236099Sdes}; 184236099Sdes 185236099Sdesstatic const char *hello_world[] = { 186236099Sdes "hello", 187236099Sdes "world", 188236099Sdes NULL 189236099Sdes}; 190236099Sdes 191236099Sdes 192236099Sdes/*************************************************************************** 193236099Sdes * Lines without words 194236099Sdes */ 195236099Sdes 196236099SdesT_FUNC(empty_input, "empty input") 197236099Sdes{ 198236099Sdes int ret; 199236099Sdes 200236099Sdes orlv_open(); 201236099Sdes ret = orlv_expect(NULL, 0 /*lines*/, 1 /*eof*/); 202236099Sdes orlv_close(); 203236099Sdes return (ret); 204236099Sdes} 205236099Sdes 206236099SdesT_FUNC(empty_line, "empty line") 207236099Sdes{ 208236099Sdes int ret; 209236099Sdes 210236099Sdes orlv_open(); 211236099Sdes orlv_output("\n"); 212236099Sdes orlv_rewind(); 213236099Sdes ret = orlv_expect(empty, 1 /*lines*/, 0 /*eof*/); 214236099Sdes orlv_close(); 215236099Sdes return (ret); 216236099Sdes} 217236099Sdes 218236099SdesT_FUNC(unterminated_empty_line, "unterminated empty line") 219236099Sdes{ 220236099Sdes int ret; 221236099Sdes 222236099Sdes orlv_open(); 223236099Sdes orlv_output(" "); 224236099Sdes orlv_rewind(); 225236099Sdes ret = orlv_expect(NULL, 0 /*lines*/, 1 /*eof*/); 226236099Sdes orlv_close(); 227236099Sdes return (ret); 228236099Sdes} 229236099Sdes 230236099SdesT_FUNC(whitespace, "whitespace") 231236099Sdes{ 232236099Sdes int ret; 233236099Sdes 234236099Sdes orlv_open(); 235236099Sdes orlv_output(" \n"); 236236099Sdes orlv_rewind(); 237236099Sdes ret = orlv_expect(empty, 1 /*lines*/, 0 /*eof*/); 238236099Sdes orlv_close(); 239236099Sdes return (ret); 240236099Sdes} 241236099Sdes 242236099SdesT_FUNC(comment, "comment") 243236099Sdes{ 244236099Sdes int ret; 245236099Sdes 246236099Sdes orlv_open(); 247236099Sdes orlv_output("# comment\n"); 248236099Sdes orlv_rewind(); 249236099Sdes ret = orlv_expect(empty, 1 /*lines*/, 0 /*eof*/); 250236099Sdes orlv_close(); 251236099Sdes return (ret); 252236099Sdes} 253236099Sdes 254236099SdesT_FUNC(whitespace_before_comment, "whitespace before comment") 255236099Sdes{ 256236099Sdes int ret; 257236099Sdes 258236099Sdes orlv_open(); 259236099Sdes orlv_output(" # comment\n"); 260236099Sdes orlv_rewind(); 261236099Sdes ret = orlv_expect(empty, 1 /*lines*/, 0 /*eof*/); 262236099Sdes orlv_close(); 263236099Sdes return (ret); 264236099Sdes} 265236099Sdes 266236099Sdes 267236099Sdes/*************************************************************************** 268236099Sdes * Simple words 269236099Sdes */ 270236099Sdes 271236099SdesT_FUNC(one_word, "one word") 272236099Sdes{ 273236099Sdes int ret; 274236099Sdes 275236099Sdes orlv_open(); 276236099Sdes orlv_output("hello\n"); 277236099Sdes orlv_rewind(); 278236099Sdes ret = orlv_expect(hello, 1 /*lines*/, 0 /*eof*/); 279236099Sdes orlv_close(); 280236099Sdes return (ret); 281236099Sdes} 282236099Sdes 283236099SdesT_FUNC(two_words, "two words") 284236099Sdes{ 285236099Sdes int ret; 286236099Sdes 287236099Sdes orlv_open(); 288236099Sdes orlv_output("hello world\n"); 289236099Sdes orlv_rewind(); 290236099Sdes ret = orlv_expect(hello_world, 1 /*lines*/, 0 /*eof*/); 291236099Sdes orlv_close(); 292236099Sdes return (ret); 293236099Sdes} 294236099Sdes 295236099SdesT_FUNC(unterminated_line, "unterminated line") 296236099Sdes{ 297236099Sdes int ret; 298236099Sdes 299236099Sdes orlv_open(); 300236099Sdes orlv_output("hello world"); 301236099Sdes orlv_rewind(); 302236099Sdes ret = orlv_expect(hello_world, 0 /*lines*/, 1 /*eof*/); 303236099Sdes orlv_close(); 304236099Sdes return (ret); 305236099Sdes} 306236099Sdes 307236099Sdes 308236099Sdes/*************************************************************************** 309236099Sdes * Boilerplate 310236099Sdes */ 311236099Sdes 312236099Sdesconst struct t_test *t_plan[] = { 313236099Sdes T(empty_input), 314236099Sdes T(empty_line), 315236099Sdes T(unterminated_empty_line), 316236099Sdes T(whitespace), 317236099Sdes T(comment), 318236099Sdes T(whitespace_before_comment), 319236099Sdes 320236099Sdes T(one_word), 321236099Sdes T(two_words), 322236099Sdes T(unterminated_line), 323236099Sdes 324236099Sdes NULL 325236099Sdes}; 326236099Sdes 327236099Sdesconst struct t_test ** 328236099Sdest_prepare(int argc, char *argv[]) 329236099Sdes{ 330236099Sdes 331236099Sdes (void)argc; 332236099Sdes (void)argv; 333236099Sdes snprintf(filename, sizeof filename, "%s.%d.tmp", t_progname, getpid()); 334236099Sdes if (filename == NULL) 335236099Sdes err(1, "asprintf()"); 336236099Sdes return (t_plan); 337236099Sdes} 338236099Sdes 339236099Sdesvoid 340236099Sdest_cleanup(void) 341236099Sdes{ 342236099Sdes} 343