source: openpam/trunk/t/t_openpam_readword.c @ 578

Last change on this file since 578 was 578, checked in by des, 3 years ago

As previously mentioned, move from 2-clause BSD to 3-clause BSD.

  • Property svn:keywords set to Id
File size: 16.2 KB
Line 
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 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 *    products derived from this software without specific prior written
16 *    permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id$
31 */
32
33#ifdef HAVE_CONFIG_H
34# include "config.h"
35#endif
36
37#include <err.h>
38#include <errno.h>
39#include <fcntl.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45#include <security/pam_appl.h>
46#include <security/openpam.h>
47
48#include "t.h"
49
50static char filename[1024];
51static FILE *f;
52
53/*
54 * Open the temp file and immediately unlink it so it doesn't leak in case
55 * of premature exit.
56 */
57static void
58orw_open(void)
59{
60        int fd;
61
62        if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0)
63                err(1, "%s(): %s", __func__, filename);
64        if ((f = fdopen(fd, "r+")) == NULL)
65                err(1, "%s(): %s", __func__, filename);
66        if (unlink(filename) < 0)
67                err(1, "%s(): %s", __func__, filename);
68}
69
70/*
71 * Write text to the temp file.
72 */
73static void
74orw_output(const char *fmt, ...)
75{
76        va_list ap;
77
78        va_start(ap, fmt);
79        vfprintf(f, fmt, ap);
80        va_end(ap);
81        if (ferror(f))
82                err(1, "%s", filename);
83}
84
85/*
86 * Rewind the temp file.
87 */
88static void
89orw_rewind(void)
90{
91
92        errno = 0;
93        rewind(f);
94        if (errno != 0)
95                err(1, "%s(): %s", __func__, filename);
96}
97
98/*
99 * Read a word from the temp file and verify that the result matches our
100 * expectations: whether a word was read at all, how many lines were read
101 * (in case of quoted or escaped newlines), whether we reached the end of
102 * the file and whether we reached the end of the line.
103 */
104static int
105orw_expect(const char *expected, int lines, int eof, int eol)
106{
107        int ch, lineno = 0;
108        char *got;
109        size_t len;
110
111        got = openpam_readword(f, &lineno, &len);
112        if (ferror(f))
113                err(1, "%s(): %s", __func__, filename);
114        if (expected != NULL && got == NULL) {
115                t_verbose("expected <<%s>>, got nothing\n", expected);
116                return (0);
117        }
118        if (expected == NULL && got != NULL) {
119                t_verbose("expected nothing, got <<%s>>\n", got);
120                return (0);
121        }
122        if (expected != NULL && got != NULL && strcmp(expected, got) != 0) {
123                t_verbose("expected <<%s>>, got <<%s>>\n", expected, got);
124                return (0);
125        }
126        if (lineno != lines) {
127                t_verbose("expected to advance %d lines, advanced %d lines\n",
128                    lines, lineno);
129                return (0);
130        }
131        if (eof && !feof(f)) {
132                t_verbose("expected EOF, but didn't get it\n");
133                return (0);
134        }
135        if (!eof && feof(f)) {
136                t_verbose("didn't expect EOF, but got it anyway\n");
137                return (0);
138        }
139        ch = fgetc(f);
140        if (ferror(f))
141                err(1, "%s(): %s", __func__, filename);
142        if (eol && ch != '\n') {
143                t_verbose("expected EOL, but didn't get it\n");
144                return (0);
145        }
146        if (!eol && ch == '\n') {
147                t_verbose("didn't expect EOL, but got it anyway\n");
148                return (0);
149        }
150        if (ch != EOF)
151                ungetc(ch, f);
152        return (1);
153}
154
155/*
156 * Close the temp file.
157 */
158void
159orw_close(void)
160{
161
162        if (fclose(f) != 0)
163                err(1, "%s(): %s", __func__, filename);
164        f = NULL;
165}
166
167
168/***************************************************************************
169 * Lines without words
170 */
171
172T_FUNC(empty_input, "empty input")
173{
174        int ret;
175
176        orw_open();
177        ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
178        orw_close();
179        return (ret);
180}
181
182T_FUNC(empty_line, "empty line")
183{
184        int ret;
185
186        orw_open();
187        orw_output("\n");
188        orw_rewind();
189        ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
190        orw_close();
191        return (ret);
192}
193
194T_FUNC(unterminated_line, "unterminated line")
195{
196        int ret;
197
198        orw_open();
199        orw_output(" ");
200        orw_rewind();
201        ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
202        orw_close();
203        return (ret);
204}
205
206T_FUNC(single_whitespace, "single whitespace")
207{
208        int ret;
209
210        orw_open();
211        orw_output(" \n");
212        orw_rewind();
213        ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
214        orw_close();
215        return (ret);
216}
217
218T_FUNC(multiple_whitespace, "multiple whitespace")
219{
220        int ret;
221
222        orw_open();
223        orw_output(" \t\r\n");
224        orw_rewind();
225        ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
226        orw_close();
227        return (ret);
228}
229
230T_FUNC(comment, "comment")
231{
232        int ret;
233
234        orw_open();
235        orw_output("# comment\n");
236        orw_rewind();
237        ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
238        orw_close();
239        return (ret);
240}
241
242T_FUNC(whitespace_before_comment, "whitespace before comment")
243{
244        int ret;
245
246        orw_open();
247        orw_output(" # comment\n");
248        orw_rewind();
249        ret = orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
250        orw_close();
251        return (ret);
252}
253
254
255/***************************************************************************
256 * Simple cases - no quotes or escapes
257 */
258
259T_FUNC(single_word, "single word")
260{
261        const char *word = "hello";
262        int ret;
263
264        orw_open();
265        orw_output("%s\n", word);
266        orw_rewind();
267        ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
268        orw_close();
269        return (ret);
270}
271
272T_FUNC(single_whitespace_before_word, "single whitespace before word")
273{
274        const char *word = "hello";
275        int ret;
276
277        orw_open();
278        orw_output(" %s\n", word);
279        orw_rewind();
280        ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
281        orw_close();
282        return (ret);
283}
284
285T_FUNC(double_whitespace_before_word, "double whitespace before word")
286{
287        const char *word = "hello";
288        int ret;
289
290        orw_open();
291        orw_output("  %s\n", word);
292        orw_rewind();
293        ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
294        orw_close();
295        return (ret);
296}
297
298T_FUNC(single_whitespace_after_word, "single whitespace after word")
299{
300        const char *word = "hello";
301        int ret;
302
303        orw_open();
304        orw_output("%s \n", word);
305        orw_rewind();
306        ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
307        orw_close();
308        return (ret);
309}
310
311T_FUNC(double_whitespace_after_word, "double whitespace after word")
312{
313        const char *word = "hello";
314        int ret;
315
316        orw_open();
317        orw_output("%s  \n", word);
318        orw_rewind();
319        ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/);
320        orw_close();
321        return (ret);
322}
323
324T_FUNC(comment_after_word, "comment after word")
325{
326        const char *word = "hello";
327        int ret;
328
329        orw_open();
330        orw_output("%s # comment\n", word);
331        orw_rewind();
332        ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
333            orw_expect(NULL, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
334        orw_close();
335        return (ret);
336}
337
338T_FUNC(word_containing_hash, "word containing hash")
339{
340        const char *word = "hello#world";
341        int ret;
342
343        orw_open();
344        orw_output("%s\n", word);
345        orw_rewind();
346        ret = orw_expect(word, 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
347        orw_close();
348        return (ret);
349}
350
351T_FUNC(two_words, "two words")
352{
353        const char *word[] = { "hello", "world" };
354        int ret;
355
356        orw_open();
357        orw_output("%s %s\n", word[0], word[1]);
358        orw_rewind();
359        ret = orw_expect(word[0], 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
360            orw_expect(word[1], 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
361        orw_close();
362        return (ret);
363}
364
365
366/***************************************************************************
367 * Escapes
368 */
369
370T_FUNC(naked_escape, "naked escape")
371{
372        int ret;
373
374        orw_open();
375        orw_output("\\");
376        orw_rewind();
377        ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
378        orw_close();
379        return (ret);
380}
381
382T_FUNC(escaped_escape, "escaped escape")
383{
384        int ret;
385
386        orw_open();
387        orw_output("\\\\\n");
388        orw_rewind();
389        ret = orw_expect("\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
390        orw_close();
391        return (ret);
392}
393
394T_FUNC(escaped_whitespace, "escaped whitespace")
395{
396        int ret;
397
398        orw_open();
399        orw_output("\\  \\\t \\\r\n");
400        orw_rewind();
401        ret = orw_expect(" ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
402            orw_expect("\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
403            orw_expect("\r", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
404        orw_close();
405        return (ret);
406}
407
408T_FUNC(escaped_newline_before_word, "escaped newline before word")
409{
410        int ret;
411
412        orw_open();
413        orw_output("\\\nhello world\n");
414        orw_rewind();
415        ret = orw_expect("hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
416        orw_close();
417        return (ret);
418}
419
420T_FUNC(escaped_newline_within_word, "escaped newline within word")
421{
422        int ret;
423
424        orw_open();
425        orw_output("hello\\\nworld\n");
426        orw_rewind();
427        ret = orw_expect("helloworld", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
428        orw_close();
429        return (ret);
430}
431
432T_FUNC(escaped_newline_after_word, "escaped newline after word")
433{
434        int ret;
435
436        orw_open();
437        orw_output("hello\\\n world\n");
438        orw_rewind();
439        ret = orw_expect("hello", 1 /*lines*/, 0 /*eof*/, 0 /*eol*/);
440        orw_close();
441        return (ret);
442}
443
444T_FUNC(escaped_letter, "escaped letter")
445{
446        int ret;
447
448        orw_open();
449        orw_output("\\z\n");
450        orw_rewind();
451        ret = orw_expect("z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
452        orw_close();
453        return (ret);
454}
455
456
457/***************************************************************************
458 * Quotes
459 */
460
461T_FUNC(naked_single_quote, "naked single quote")
462{
463        int ret;
464
465        orw_open();
466        orw_output("'");
467        orw_rewind();
468        ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
469        orw_close();
470        return (ret);
471}
472
473T_FUNC(naked_double_quote, "naked double quote")
474{
475        int ret;
476
477        orw_open();
478        orw_output("\"");
479        orw_rewind();
480        ret = orw_expect(NULL, 0 /*lines*/, 1 /*eof*/, 0 /*eol*/);
481        orw_close();
482        return (ret);
483}
484
485T_FUNC(empty_single_quotes, "empty single quotes")
486{
487        int ret;
488
489        orw_open();
490        orw_output("''\n");
491        orw_rewind();
492        ret = orw_expect("", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
493        orw_close();
494        return (ret);
495}
496
497T_FUNC(empty_double_quotes, "empty double quotes")
498{
499        int ret;
500
501        orw_open();
502        orw_output("\"\"\n");
503        orw_rewind();
504        ret = orw_expect("", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
505        orw_close();
506        return (ret);
507}
508
509T_FUNC(single_quotes_within_double_quotes, "single quotes within double quotes")
510{
511        int ret;
512
513        orw_open();
514        orw_output("\"' '\"\n");
515        orw_rewind();
516        ret = orw_expect("' '", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
517        orw_close();
518        return (ret);
519}
520
521T_FUNC(double_quotes_within_single_quotes, "double quotes within single quotes")
522{
523        int ret;
524
525        orw_open();
526        orw_output("'\" \"'\n");
527        orw_rewind();
528        ret = orw_expect("\" \"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
529        orw_close();
530        return (ret);
531}
532
533T_FUNC(single_quoted_whitespace, "single-quoted whitespace")
534{
535        int ret;
536
537        orw_open();
538        orw_output("' ' '\t' '\r' '\n'\n");
539        orw_rewind();
540        ret = orw_expect(" ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
541            orw_expect("\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
542            orw_expect("\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
543            orw_expect("\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
544        orw_close();
545        return (ret);
546}
547
548T_FUNC(double_quoted_whitespace, "double-quoted whitespace")
549{
550        int ret;
551
552        orw_open();
553        orw_output("\" \" \"\t\" \"\r\" \"\n\"\n");
554        orw_rewind();
555        ret = orw_expect(" ", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
556            orw_expect("\t", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
557            orw_expect("\r", 0 /*lines*/, 0 /*eof*/, 0 /*eol*/) &&
558            orw_expect("\n", 1 /*lines*/, 0 /*eof*/, 1 /*eol*/);
559        orw_close();
560        return (ret);
561}
562
563T_FUNC(single_quoted_words, "single-quoted words")
564{
565        int ret;
566
567        orw_open();
568        orw_output("'hello world'\n");
569        orw_rewind();
570        ret = orw_expect("hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
571        orw_close();
572        return (ret);
573}
574
575T_FUNC(double_quoted_words, "double-quoted words")
576{
577        int ret;
578
579        orw_open();
580        orw_output("\"hello world\"\n");
581        orw_rewind();
582        ret = orw_expect("hello world", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
583        orw_close();
584        return (ret);
585}
586
587
588/***************************************************************************
589 * Combinations of escape and quotes
590 */
591
592T_FUNC(escaped_single_quote,
593    "escaped single quote")
594{
595        int ret;
596
597        orw_open();
598        orw_output("\\'\n");
599        orw_rewind();
600        ret = orw_expect("'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
601        orw_close();
602        return (ret);
603}
604
605T_FUNC(escaped_double_quote,
606    "escaped double quote")
607{
608        int ret;
609
610        orw_open();
611        orw_output("\\\"\n");
612        orw_rewind();
613        ret = orw_expect("\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
614        orw_close();
615        return (ret);
616}
617
618T_FUNC(escaped_letter_within_single_quotes,
619    "escaped letter within single quotes")
620{
621        int ret;
622
623        orw_open();
624        orw_output("'\\z'\n");
625        orw_rewind();
626        ret = orw_expect("\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
627        orw_close();
628        return (ret);
629}
630
631T_FUNC(escaped_letter_within_double_quotes,
632    "escaped letter within double quotes")
633{
634        int ret;
635
636        orw_open();
637        orw_output("\"\\z\"\n");
638        orw_rewind();
639        ret = orw_expect("\\z", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
640        orw_close();
641        return (ret);
642}
643
644T_FUNC(escaped_escape_within_single_quotes,
645    "escaped escape within single quotes")
646{
647        int ret;
648
649        orw_open();
650        orw_output("'\\\\'\n");
651        orw_rewind();
652        ret = orw_expect("\\\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
653        orw_close();
654        return (ret);
655}
656
657T_FUNC(escaped_escape_within_double_quotes,
658    "escaped escape within double quotes")
659{
660        int ret;
661
662        orw_open();
663        orw_output("\"\\\\\"\n");
664        orw_rewind();
665        ret = orw_expect("\\", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
666        orw_close();
667        return (ret);
668}
669
670T_FUNC(escaped_single_quote_within_single_quotes,
671    "escaped single quote within single quotes")
672{
673        int ret;
674
675        orw_open();
676        orw_output("'\\''\n");
677        orw_rewind();
678        ret = orw_expect(NULL, 1 /*lines*/, 1 /*eof*/, 0 /*eol*/);
679        orw_close();
680        return (ret);
681}
682
683T_FUNC(escaped_double_quote_within_single_quotes,
684    "escaped double quote within single quotes")
685{
686        int ret;
687
688        orw_open();
689        orw_output("'\\\"'\n");
690        orw_rewind();
691        ret = orw_expect("\\\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
692        orw_close();
693        return (ret);
694}
695
696T_FUNC(escaped_single_quote_within_double_quotes,
697    "escaped single quote within double quotes")
698{
699        int ret;
700
701        orw_open();
702        orw_output("\"\\'\"\n");
703        orw_rewind();
704        ret = orw_expect("\\'", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
705        orw_close();
706        return (ret);
707}
708
709T_FUNC(escaped_double_quote_within_double_quotes,
710    "escaped double quote within double quotes")
711{
712        int ret;
713
714        orw_open();
715        orw_output("\"\\\"\"\n");
716        orw_rewind();
717        ret = orw_expect("\"", 0 /*lines*/, 0 /*eof*/, 1 /*eol*/);
718        orw_close();
719        return (ret);
720}
721
722
723/***************************************************************************
724 * Boilerplate
725 */
726
727const struct t_test *t_plan[] = {
728        T(empty_input),
729        T(empty_line),
730        T(single_whitespace),
731        T(multiple_whitespace),
732        T(comment),
733        T(whitespace_before_comment),
734
735        T(single_word),
736        T(single_whitespace_before_word),
737        T(double_whitespace_before_word),
738        T(single_whitespace_after_word),
739        T(double_whitespace_after_word),
740        T(comment_after_word),
741        T(word_containing_hash),
742        T(two_words),
743
744        T(naked_escape),
745        T(escaped_escape),
746        T(escaped_whitespace),
747        T(escaped_newline_before_word),
748        T(escaped_newline_within_word),
749        T(escaped_newline_after_word),
750        T(escaped_letter),
751
752        T(naked_single_quote),
753        T(naked_double_quote),
754        T(empty_single_quotes),
755        T(empty_double_quotes),
756        T(single_quotes_within_double_quotes),
757        T(double_quotes_within_single_quotes),
758        T(single_quoted_whitespace),
759        T(double_quoted_whitespace),
760        T(single_quoted_words),
761        T(double_quoted_words),
762
763        T(escaped_single_quote),
764        T(escaped_double_quote),
765        T(escaped_letter_within_single_quotes),
766        T(escaped_letter_within_double_quotes),
767        T(escaped_escape_within_single_quotes),
768        T(escaped_escape_within_double_quotes),
769        T(escaped_single_quote_within_single_quotes),
770        T(escaped_double_quote_within_single_quotes),
771        T(escaped_single_quote_within_double_quotes),
772        T(escaped_double_quote_within_double_quotes),
773
774        NULL
775};
776
777const struct t_test **
778t_prepare(int argc, char *argv[])
779{
780
781        (void)argc;
782        (void)argv;
783        snprintf(filename, sizeof filename, "%s.%d.tmp", t_progname, getpid());
784        if (filename == NULL)
785                err(1, "asprintf()");
786        return (t_plan);
787}
788
789void
790t_cleanup(void)
791{
792}
Note: See TracBrowser for help on using the repository browser.