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