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