openpam_readline.c revision 186063
1258331Smarkj/*-
2258331Smarkj * Copyright (c) 2003 Networks Associates Technology, Inc.
3258331Smarkj * Copyright (c) 2004-2007 Dag-Erling Sm��rgrav
4258331Smarkj * All rights reserved.
5258331Smarkj *
6258331Smarkj * This software was developed for the FreeBSD Project by ThinkSec AS and
7258331Smarkj * Network Associates Laboratories, the Security Research Division of
8258331Smarkj * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
9258331Smarkj * ("CBOSS"), as part of the DARPA CHATS research program.
10258331Smarkj *
11258331Smarkj * Redistribution and use in source and binary forms, with or without
12258331Smarkj * modification, are permitted provided that the following conditions
13258331Smarkj * are met:
14258331Smarkj * 1. Redistributions of source code must retain the above copyright
15258331Smarkj *    notice, this list of conditions and the following disclaimer.
16258331Smarkj * 2. Redistributions in binary form must reproduce the above copyright
17258331Smarkj *    notice, this list of conditions and the following disclaimer in the
18258331Smarkj *    documentation and/or other materials provided with the distribution.
19258331Smarkj * 3. The name of the author may not be used to endorse or promote
20258331Smarkj *    products derived from this software without specific prior written
21258331Smarkj *    permission.
22258331Smarkj *
23258331Smarkj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24258331Smarkj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25258331Smarkj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26258331Smarkj * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27258331Smarkj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28258331Smarkj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29258331Smarkj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30258331Smarkj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31258331Smarkj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32258331Smarkj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33291238Skevlo * SUCH DAMAGE.
34258331Smarkj *
35258331Smarkj * $Id: openpam_readline.c 408 2007-12-21 11:36:24Z des $
36258331Smarkj */
37258331Smarkj
38258331Smarkj#include <ctype.h>
39258331Smarkj#include <stdio.h>
40258331Smarkj#include <stdlib.h>
41258331Smarkj
42258331Smarkj#include <security/pam_appl.h>
43258331Smarkj#include "openpam_impl.h"
44258617Slwhsu
45258331Smarkj#define MIN_LINE_LENGTH 128
46258331Smarkj
47258331Smarkj/*
48258331Smarkj * OpenPAM extension
49258331Smarkj *
50291238Skevlo * Read a line from a file.
51258331Smarkj */
52258331Smarkj
53258331Smarkjchar *
54258331Smarkjopenpam_readline(FILE *f, int *lineno, size_t *lenp)
55258331Smarkj{
56258331Smarkj	char *line;
57258331Smarkj	size_t len, size;
58258331Smarkj	int ch;
59258331Smarkj
60258331Smarkj	if ((line = malloc(MIN_LINE_LENGTH)) == NULL)
61258331Smarkj		return (NULL);
62258331Smarkj	size = MIN_LINE_LENGTH;
63258331Smarkj	len = 0;
64258331Smarkj
65258331Smarkj#define line_putch(ch) do { \
66258331Smarkj	if (len >= size - 1) { \
67258331Smarkj		char *tmp = realloc(line, size *= 2); \
68258331Smarkj		if (tmp == NULL) \
69258331Smarkj			goto fail; \
70258331Smarkj		line = tmp; \
71258331Smarkj	} \
72258331Smarkj	line[len++] = ch; \
73258331Smarkj	line[len] = '\0'; \
74258331Smarkj} while (0)
75258331Smarkj
76258331Smarkj	for (;;) {
77258331Smarkj		ch = fgetc(f);
78258331Smarkj		/* strip comment */
79258331Smarkj		if (ch == '#') {
80258331Smarkj			do {
81258331Smarkj				ch = fgetc(f);
82258331Smarkj			} while (ch != EOF && ch != '\n');
83258331Smarkj		}
84258331Smarkj		/* eof */
85258331Smarkj		if (ch == EOF) {
86258331Smarkj			/* remove trailing whitespace */
87258331Smarkj			while (len > 0 && isspace((int)line[len - 1]))
88258331Smarkj				--len;
89258331Smarkj			line[len] = '\0';
90258331Smarkj			if (len == 0)
91258331Smarkj				goto fail;
92258331Smarkj			break;
93258331Smarkj		}
94258331Smarkj		/* eol */
95258331Smarkj		if (ch == '\n') {
96258331Smarkj			if (lineno != NULL)
97258331Smarkj				++*lineno;
98258331Smarkj
99258331Smarkj			/* remove trailing whitespace */
100258331Smarkj			while (len > 0 && isspace((int)line[len - 1]))
101258331Smarkj				--len;
102258331Smarkj			line[len] = '\0';
103258331Smarkj			/* skip blank lines */
104258331Smarkj			if (len == 0)
105258331Smarkj				continue;
106258331Smarkj			/* continuation */
107258331Smarkj			if (line[len - 1] == '\\') {
108258331Smarkj				line[--len] = '\0';
109258331Smarkj				/* fall through to whitespace case */
110258331Smarkj			} else {
111258331Smarkj				break;
112258331Smarkj			}
113258331Smarkj		}
114258331Smarkj		/* whitespace */
115258331Smarkj		if (isspace(ch)) {
116258331Smarkj			/* ignore leading whitespace */
117258331Smarkj			/* collapse linear whitespace */
118258331Smarkj			if (len > 0 && line[len - 1] != ' ')
119258331Smarkj				line_putch(' ');
120258331Smarkj			continue;
121258331Smarkj		}
122258331Smarkj		/* anything else */
123258331Smarkj		line_putch(ch);
124258331Smarkj	}
125258331Smarkj
126258331Smarkj	if (lenp != NULL)
127258331Smarkj		*lenp = len;
128258331Smarkj	return (line);
129258331Smarkj fail:
130258331Smarkj	FREE(line);
131258331Smarkj	return (NULL);
132258331Smarkj}
133258331Smarkj
134258331Smarkj/**
135258331Smarkj * The =openpam_readline function reads a line from a file, and returns it
136258331Smarkj * in a NUL-terminated buffer allocated with =malloc.
137258331Smarkj *
138258331Smarkj * The =openpam_readline function performs a certain amount of processing
139258331Smarkj * on the data it reads.
140258331Smarkj * Comments (introduced by a hash sign) are stripped, as is leading and
141267938Sbapt * trailing whitespace.
142258331Smarkj * Any amount of linear whitespace is collapsed to a single space.
143258331Smarkj * Blank lines are ignored.
144258331Smarkj * If a line ends in a backslash, the backslash is stripped and the next
145267938Sbapt * line is appended.
146258331Smarkj *
147267938Sbapt * If =lineno is not =NULL, the integer variable it points to is
148258331Smarkj * incremented every time a newline character is read.
149267938Sbapt *
150258331Smarkj * If =lenp is not =NULL, the length of the line (not including the
151258331Smarkj * terminating NUL character) is stored in the variable it points to.
152258331Smarkj *
153 * The caller is responsible for releasing the returned buffer by passing
154 * it to =free.
155 */
156