Import OpenPAM Micrampelis.
[dragonfly.git] / contrib / openpam / lib / openpam_readlinev.c
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: openpam_readlinev.c 588 2012-04-08 11:52:25Z des $
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40
41 #include <security/pam_appl.h>
42
43 #include "openpam_impl.h"
44
45 #define MIN_WORDV_SIZE  32
46
47 /*
48  * OpenPAM extension
49  *
50  * Read a line from a file and split it into words.
51  */
52
53 char **
54 openpam_readlinev(FILE *f, int *lineno, int *lenp)
55 {
56         char *word, **wordv, **tmp;
57         size_t wordlen, wordvsize;
58         int ch, serrno, wordvlen;
59
60         wordvsize = MIN_WORDV_SIZE;
61         wordvlen = 0;
62         if ((wordv = malloc(wordvsize * sizeof *wordv)) == NULL) {
63                 openpam_log(PAM_LOG_ERROR, "malloc(): %m");
64                 errno = ENOMEM;
65                 return (NULL);
66         }
67         wordv[wordvlen] = NULL;
68         while ((word = openpam_readword(f, lineno, &wordlen)) != NULL) {
69                 if ((unsigned int)wordvlen + 1 >= wordvsize) {
70                         /* need to expand the array */
71                         wordvsize *= 2;
72                         tmp = realloc(wordv, wordvsize * sizeof *wordv);
73                         if (tmp == NULL) {
74                                 openpam_log(PAM_LOG_ERROR, "malloc(): %m");
75                                 errno = ENOMEM;
76                                 break;
77                         }
78                         wordv = tmp;
79                 }
80                 /* insert our word */
81                 wordv[wordvlen++] = word;
82                 wordv[wordvlen] = NULL;
83         }
84         if (errno != 0) {
85                 /* I/O error or out of memory */
86                 serrno = errno;
87                 while (wordvlen--)
88                         free(wordv[wordvlen]);
89                 free(wordv);
90                 errno = serrno;
91                 return (NULL);
92         }
93         /* assert(!ferror(f)) */
94         ch = fgetc(f);
95         /* assert(ch == EOF || ch == '\n') */
96         if (ch == EOF && wordvlen == 0) {
97                 free(wordv);
98                 return (NULL);
99         }
100         if (ch == '\n' && lineno != NULL)
101                 ++*lineno;
102         if (lenp != NULL)
103                 *lenp = wordvlen;
104         return (wordv);
105 }
106
107 /**
108  * The =openpam_readlinev function reads a line from a file, splits it
109  * into words according to the rules described in the =openpam_readword
110  * manual page, and returns a list of those words.
111  *
112  * If =lineno is not =NULL, the integer variable it points to is
113  * incremented every time a newline character is read.
114  * This includes quoted or escaped newline characters and the newline
115  * character at the end of the line.
116  *
117  * If =lenp is not =NULL, the number of words on the line is stored in the
118  * variable to which it points.
119  *
120  * RETURN VALUES
121  *
122  * If successful, the =openpam_readlinev function returns a pointer to a
123  * dynamically allocated array of pointers to individual dynamically
124  * allocated NUL-terminated strings, each containing a single word, in the
125  * order in which they were encountered on the line.
126  * The array is terminated by a =NULL pointer.
127  *
128  * The caller is responsible for freeing both the array and the individual
129  * strings by passing each of them to =!free.
130  *
131  * If the end of the line was reached before any words were read,
132  * =openpam_readlinev returns a pointer to a dynamically allocated array
133  * containing a single =NULL pointer.
134  *
135  * The =openpam_readlinev function can fail and return =NULL for one of
136  * four reasons:
137  *
138  *  - The end of the file was reached before any words were read; :errno is
139  *    zero, =!ferror returns zero, and =!feof returns a non-zero value.
140  *
141  *  - The end of the file was reached while a quote or backslash escape
142  *    was in effect; :errno is set to =EINVAL, =!ferror returns zero, and
143  *    =!feof returns a non-zero value.
144  *
145  *  - An error occurred while reading from the file; :errno is non-zero,
146  *    =!ferror returns a non-zero value and =!feof returns zero.
147  *
148  *  - A =!malloc or =!realloc call failed; :errno is set to =ENOMEM,
149  *    =!ferror returns a non-zero value, and =!feof may or may not return
150  *    a non-zero value.
151  *
152  * >openpam_readline
153  * >openpam_readword
154  *
155  * AUTHOR DES
156  */