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