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