openpam_readline.c revision 168463
1115619Sdes/*-
2115619Sdes * Copyright (c) 2003 Networks Associates Technology, Inc.
3115619Sdes * All rights reserved.
4115619Sdes *
5115619Sdes * This software was developed for the FreeBSD Project by ThinkSec AS and
6115619Sdes * Network Associates Laboratories, the Security Research Division of
7115619Sdes * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
8115619Sdes * ("CBOSS"), as part of the DARPA CHATS research program.
9115619Sdes *
10115619Sdes * Redistribution and use in source and binary forms, with or without
11115619Sdes * modification, are permitted provided that the following conditions
12115619Sdes * are met:
13115619Sdes * 1. Redistributions of source code must retain the above copyright
14115619Sdes *    notice, this list of conditions and the following disclaimer.
15115619Sdes * 2. Redistributions in binary form must reproduce the above copyright
16115619Sdes *    notice, this list of conditions and the following disclaimer in the
17115619Sdes *    documentation and/or other materials provided with the distribution.
18115619Sdes * 3. The name of the author may not be used to endorse or promote
19115619Sdes *    products derived from this software without specific prior written
20115619Sdes *    permission.
21115619Sdes *
22115619Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23115619Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24115619Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25115619Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26115619Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27115619Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28115619Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29115619Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30115619Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31115619Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32115619Sdes * SUCH DAMAGE.
33115619Sdes *
34168463Sdes * $Id: openpam_readline.c 380 2006-03-14 14:42:09Z des $
35115619Sdes */
36115619Sdes
37115619Sdes#include <ctype.h>
38115619Sdes#include <stdio.h>
39115619Sdes#include <stdlib.h>
40115619Sdes
41115619Sdes#include <security/pam_appl.h>
42115619Sdes#include "openpam_impl.h"
43115619Sdes
44115619Sdes#define MIN_LINE_LENGTH 128
45115619Sdes
46115619Sdes/*
47115619Sdes * OpenPAM extension
48115619Sdes *
49115619Sdes * Read a line from a file.
50115619Sdes */
51115619Sdes
52115619Sdeschar *
53115619Sdesopenpam_readline(FILE *f, int *lineno, size_t *lenp)
54115619Sdes{
55168463Sdes	char *line;
56115619Sdes	size_t len, size;
57115619Sdes	int ch;
58115619Sdes
59115619Sdes	if ((line = malloc(MIN_LINE_LENGTH)) == NULL)
60115619Sdes		return (NULL);
61115619Sdes	size = MIN_LINE_LENGTH;
62115619Sdes	len = 0;
63115619Sdes
64115619Sdes#define line_putch(ch) do { \
65115619Sdes	if (len >= size - 1) { \
66168463Sdes		char *tmp = realloc(line, size *= 2); \
67115619Sdes		if (tmp == NULL) \
68115619Sdes			goto fail; \
69115619Sdes		line = tmp; \
70115619Sdes	} \
71115619Sdes	line[len++] = ch; \
72115619Sdes	line[len] = '\0'; \
73115619Sdes} while (0)
74115619Sdes
75115619Sdes	for (;;) {
76115619Sdes		ch = fgetc(f);
77115619Sdes		/* strip comment */
78115619Sdes		if (ch == '#') {
79115619Sdes			do {
80115619Sdes				ch = fgetc(f);
81115619Sdes			} while (ch != EOF && ch != '\n');
82115619Sdes		}
83115619Sdes		/* eof */
84115619Sdes		if (ch == EOF) {
85115619Sdes			/* remove trailing whitespace */
86168463Sdes			while (len > 0 && isspace((int)line[len - 1]))
87115619Sdes				--len;
88115619Sdes			line[len] = '\0';
89115619Sdes			if (len == 0)
90115619Sdes				goto fail;
91115619Sdes			break;
92115619Sdes		}
93115619Sdes		/* eol */
94115619Sdes		if (ch == '\n') {
95115619Sdes			if (lineno != NULL)
96115619Sdes				++*lineno;
97115619Sdes
98115619Sdes			/* remove trailing whitespace */
99168463Sdes			while (len > 0 && isspace((int)line[len - 1]))
100115619Sdes				--len;
101115619Sdes			line[len] = '\0';
102115619Sdes			/* skip blank lines */
103115619Sdes			if (len == 0)
104115619Sdes				continue;
105115619Sdes			/* continuation */
106115619Sdes			if (line[len - 1] == '\\') {
107115619Sdes				line[--len] = '\0';
108115619Sdes				/* fall through to whitespace case */
109115619Sdes			} else {
110115619Sdes				break;
111115619Sdes			}
112115619Sdes		}
113115619Sdes		/* whitespace */
114115619Sdes		if (isspace(ch)) {
115115619Sdes			/* ignore leading whitespace */
116115619Sdes			/* collapse linear whitespace */
117115619Sdes			if (len > 0 && line[len - 1] != ' ')
118115619Sdes				line_putch(' ');
119115619Sdes			continue;
120115619Sdes		}
121115619Sdes		/* anything else */
122115619Sdes		line_putch(ch);
123115619Sdes	}
124115619Sdes
125115619Sdes	if (lenp != NULL)
126115619Sdes		*lenp = len;
127115619Sdes	return (line);
128115619Sdes fail:
129115619Sdes	FREE(line);
130115619Sdes	return (NULL);
131115619Sdes}
132115619Sdes
133115619Sdes/**
134115619Sdes * The =openpam_readline function reads a line from a file, and returns it
135115619Sdes * in a NUL-terminated buffer allocated with =malloc.
136115619Sdes *
137115619Sdes * The =openpam_readline function performs a certain amount of processing
138115619Sdes * on the data it reads.
139115619Sdes * Comments (introduced by a hash sign) are stripped, as is leading and
140115619Sdes * trailing whitespace.
141115619Sdes * Any amount of linear whitespace is collapsed to a single space.
142115619Sdes * Blank lines are ignored.
143115619Sdes * If a line ends in a backslash, the backslash is stripped and the next
144115619Sdes * line is appended.
145115619Sdes *
146115619Sdes * If =lineno is not =NULL, the integer variable it points to is
147115619Sdes * incremented every time a newline character is read.
148115619Sdes *
149115619Sdes * If =lenp is not =NULL, the length of the line (not including the
150115619Sdes * terminating NUL character) is stored in the variable it points to.
151115619Sdes *
152115619Sdes * The caller is responsible for releasing the returned buffer by passing
153115619Sdes * it to =free.
154115619Sdes */
155