openpam_readline.c revision 115619
1233648Seadler/*-
2230491Sjimharris * Copyright (c) 2003 Networks Associates Technology, Inc.
3230491Sjimharris * All rights reserved.
4233648Seadler *
5230491Sjimharris * This software was developed for the FreeBSD Project by ThinkSec AS and
6230491Sjimharris * Network Associates Laboratories, the Security Research Division of
7230491Sjimharris * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
8230491Sjimharris * ("CBOSS"), as part of the DARPA CHATS research program.
9230491Sjimharris *
10230491Sjimharris * Redistribution and use in source and binary forms, with or without
11230491Sjimharris * modification, are permitted provided that the following conditions
12230491Sjimharris * are met:
13230491Sjimharris * 1. Redistributions of source code must retain the above copyright
14230491Sjimharris *    notice, this list of conditions and the following disclaimer.
15230491Sjimharris * 2. Redistributions in binary form must reproduce the above copyright
16233648Seadler *    notice, this list of conditions and the following disclaimer in the
17230491Sjimharris *    documentation and/or other materials provided with the distribution.
18230491Sjimharris * 3. The name of the author may not be used to endorse or promote
19230491Sjimharris *    products derived from this software without specific prior written
20230491Sjimharris *    permission.
21230491Sjimharris *
22230491Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23230491Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24230491Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25230491Sjimharris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26230491Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27230491Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28230491Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29233648Seadler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30230491Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31230491Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32230491Sjimharris * SUCH DAMAGE.
33230491Sjimharris *
34230491Sjimharris * $P4: //depot/projects/openpam/lib/openpam_readline.c#2 $
35230491Sjimharris */
36230491Sjimharris
37230491Sjimharris#include <ctype.h>
38230491Sjimharris#include <stdio.h>
39230491Sjimharris#include <stdlib.h>
40230491Sjimharris
41230491Sjimharris#include <security/pam_appl.h>
42230491Sjimharris#include "openpam_impl.h"
43230491Sjimharris
44230491Sjimharris#define MIN_LINE_LENGTH 128
45230491Sjimharris
46230491Sjimharris/*
47230491Sjimharris * OpenPAM extension
48230491Sjimharris *
49230491Sjimharris * Read a line from a file.
50230491Sjimharris */
51230491Sjimharris
52230491Sjimharrischar *
53230491Sjimharrisopenpam_readline(FILE *f, int *lineno, size_t *lenp)
54230491Sjimharris{
55232056Sbrueffer	char *line;
56230491Sjimharris	size_t len, size;
57230491Sjimharris	int ch;
58230491Sjimharris
59230491Sjimharris	if ((line = malloc(MIN_LINE_LENGTH)) == NULL)
60231615Sbrueffer		return (NULL);
61230491Sjimharris	size = MIN_LINE_LENGTH;
62230491Sjimharris	len = 0;
63230491Sjimharris
64230491Sjimharris#define line_putch(ch) do { \
65230491Sjimharris	if (len >= size - 1) { \
66230491Sjimharris		char *tmp = realloc(line, size *= 2); \
67230491Sjimharris		if (tmp == NULL) \
68230491Sjimharris			goto fail; \
69230491Sjimharris		line = tmp; \
70230491Sjimharris	} \
71230491Sjimharris	line[len++] = ch; \
72230491Sjimharris	line[len] = '\0'; \
73230491Sjimharris} while (0)
74230491Sjimharris
75230491Sjimharris	for (;;) {
76230491Sjimharris		ch = fgetc(f);
77230491Sjimharris		/* strip comment */
78230491Sjimharris		if (ch == '#') {
79230491Sjimharris			do {
80231615Sbrueffer				ch = fgetc(f);
81231615Sbrueffer			} while (ch != EOF && ch != '\n');
82231615Sbrueffer		}
83231615Sbrueffer		/* eof */
84231615Sbrueffer		if (ch == EOF) {
85230491Sjimharris			/* remove trailing whitespace */
86230491Sjimharris			while (len > 0 && isspace(line[len - 1]))
87230491Sjimharris				--len;
88230491Sjimharris			line[len] = '\0';
89233648Seadler			if (len == 0)
90230491Sjimharris				goto fail;
91230491Sjimharris			break;
92230491Sjimharris		}
93230491Sjimharris		/* eol */
94230491Sjimharris		if (ch == '\n') {
95230491Sjimharris			if (lineno != NULL)
96231615Sbrueffer				++*lineno;
97230491Sjimharris
98230491Sjimharris			/* remove trailing whitespace */
99230491Sjimharris			while (len > 0 && isspace(line[len - 1]))
100230491Sjimharris				--len;
101235317Sgjb			line[len] = '\0';
102235317Sgjb			/* skip blank lines */
103230491Sjimharris			if (len == 0)
104230491Sjimharris				continue;
105230491Sjimharris			/* continuation */
106230491Sjimharris			if (line[len - 1] == '\\') {
107230491Sjimharris				line[--len] = '\0';
108267938Sbapt				/* fall through to whitespace case */
109267938Sbapt			} else {
110267938Sbapt				break;
111267938Sbapt			}
112267938Sbapt		}
113230491Sjimharris		/* whitespace */
114230491Sjimharris		if (isspace(ch)) {
115267938Sbapt			/* ignore leading whitespace */
116			/* collapse linear whitespace */
117			if (len > 0 && line[len - 1] != ' ')
118				line_putch(' ');
119			continue;
120		}
121		/* anything else */
122		line_putch(ch);
123	}
124
125	if (lenp != NULL)
126		*lenp = len;
127	return (line);
128 fail:
129	FREE(line);
130	return (NULL);
131}
132
133/**
134 * The =openpam_readline function reads a line from a file, and returns it
135 * in a NUL-terminated buffer allocated with =malloc.
136 *
137 * The =openpam_readline function performs a certain amount of processing
138 * on the data it reads.
139 * Comments (introduced by a hash sign) are stripped, as is leading and
140 * trailing whitespace.
141 * Any amount of linear whitespace is collapsed to a single space.
142 * Blank lines are ignored.
143 * If a line ends in a backslash, the backslash is stripped and the next
144 * line is appended.
145 *
146 * If =lineno is not =NULL, the integer variable it points to is
147 * incremented every time a newline character is read.
148 *
149 * If =lenp is not =NULL, the length of the line (not including the
150 * terminating NUL character) is stored in the variable it points to.
151 *
152 * The caller is responsible for releasing the returned buffer by passing
153 * it to =free.
154 */
155