openpam_readline.c revision 115619
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 * 34115619Sdes * $P4: //depot/projects/openpam/lib/openpam_readline.c#2 $ 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{ 55115619Sdes 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) { \ 66115619Sdes 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 */ 86115619Sdes while (len > 0 && isspace(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 */ 99115619Sdes while (len > 0 && isspace(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