/*
* Interface to PAM option parsing.
*
* This interface defines a lot of macros and types with very short names, and
* hence without a lot of namespace protection. It should be included only in
* the file that's doing the option parsing and not elsewhere to remove the
* risk of clashes.
*
* The canonical version of this file is maintained in the rra-c-util package,
* which can be found at .
*
* Written by Russ Allbery
* Copyright 2020 Russ Allbery
* Copyright 2010-2011, 2013
* The Board of Trustees of the Leland Stanford Junior University
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* SPDX-License-Identifier: MIT
*/
#ifndef PAM_UTIL_OPTIONS_H
#define PAM_UTIL_OPTIONS_H 1
#include
#ifdef HAVE_KRB5
# include
#endif
#include
#include
#include
/* Forward declarations to avoid additional includes. */
struct vector;
/*
* The types of configuration values possible. STRLIST is a list data type
* that takes its default from a string value instead of a vector. For
* STRLIST, the default string value will be turned into a vector by splitting
* on comma, space, and tab. (This is the same as would be done with the
* value of a PAM setting when the target variable type is a list.)
*/
enum type
{
TYPE_BOOLEAN,
TYPE_NUMBER,
TYPE_TIME,
TYPE_STRING,
TYPE_LIST,
TYPE_STRLIST
};
/*
* Each configuration option is defined by a struct option. This specifies
* the name of the option, its offset into the configuration struct, whether
* it can be specified in a krb5.conf file, its type, and its default value if
* not set. Note that PAM configuration options are specified as strings, so
* there's no native way of representing a list argument. List values are
* always initialized by splitting a string on whitespace or commas.
*
* The default value should really be a union, but you can't initialize unions
* properly in C in a static initializer without C99 named initializer
* support, which we can't (yet) assume. So use a struct instead, and
* initialize all the members, even though we'll only care about one of them.
*
* Note that numbers set in the configuration struct created by this interface
* must be longs, not ints. There is currently no provision for unsigned
* numbers.
*
* Times take their default from defaults.number. The difference between time
* and number is in the parsing of a user-supplied value and the type of the
* stored attribute.
*/
struct option {
const char *name;
size_t location;
bool krb5_config;
enum type type;
struct {
bool boolean;
long number;
const char *string;
const struct vector *list;
} defaults;
};
/*
* The following macros are helpers to make it easier to define the table that
* specifies how to convert the configuration into a struct. They provide an
* initializer for the type and default fields.
*/
/* clang-format off */
#define BOOL(def) TYPE_BOOLEAN, { (def), 0, NULL, NULL }
#define NUMBER(def) TYPE_NUMBER, { 0, (def), NULL, NULL }
#define TIME(def) TYPE_TIME, { 0, (def), NULL, NULL }
#define STRING(def) TYPE_STRING, { 0, 0, (def), NULL }
#define LIST(def) TYPE_LIST, { 0, 0, NULL, (def) }
#define STRLIST(def) TYPE_STRLIST, { 0, 0, (def), NULL }
/* clang-format on */
/*
* The user of this file should also define a macro of the following form:
*
* #define K(name) (#name), offsetof(struct pam_config, name)
*
* Then, the definition of the necessary table for building the configuration
* will look something like this:
*
* const struct option options[] = {
* { K(aklog_homedir), true, BOOL (false) },
* { K(cells), true, LIST (NULL) },
* { K(debug), false, BOOL (false) },
* { K(minimum_uid), true, NUMBER (0) },
* { K(program), true, STRING (NULL) },
* };
*
* which provides a nice, succinct syntax for creating the table. The options
* MUST be in sorted order, since the options parsing code does a binary
* search.
*/
BEGIN_DECLS
/* Default to a hidden visibility for all internal functions. */
#pragma GCC visibility push(hidden)
/*
* Set the defaults for the PAM configuration. Takes the PAM arguments, an
* option table defined as above, and the number of entries in the table. The
* config member of the args struct must already be allocated. Returns true
* on success and false on error (generally out of memory). Errors will
* already be reported using putil_crit().
*
* This function must be called before either putil_args_krb5() or
* putil_args_parse(), since neither of those functions set defaults.
*/
bool putil_args_defaults(struct pam_args *, const struct option options[],
size_t optlen) __attribute__((__nonnull__));
/*
* Fill out options from krb5.conf. Takes the PAM args structure, the name of
* the section for the software being configured, an option table defined as
* above, and the number of entries in the table. The config member of the
* args struct must already be allocated. Only those options whose
* krb5_config attribute is true will be considered.
*
* This code automatically checks for configuration settings scoped to the
* local realm, so the default realm should be set before calling this
* function. If that's done based on a configuration option, one may need to
* pre-parse the configuration options.
*
* Returns true on success and false on an error. An error return should be
* considered fatal. Errors will already be reported using putil_crit*() or
* putil_err*() as appropriate. If Kerberos is not available, returns without
* doing anything.
*
* putil_args_defaults() should be called before this function.
*/
bool putil_args_krb5(struct pam_args *, const char *section,
const struct option options[], size_t optlen)
__attribute__((__nonnull__));
/*
* Parse the PAM arguments and fill out the provided struct. Takes the PAM
* arguments, the argument count and vector, an option table defined as above,
* and the number of entries in the table. The config member of the args
* struct must already be allocated. Returns true on success and false on
* error. An error return should be considered fatal. Errors will already be
* reported using putil_crit(). Unknown options will also be diagnosed (to
* syslog at LOG_ERR using putil_err()), but are not considered fatal errors
* and will still return true.
*
* The krb5_config option of the option configuration is ignored by this
* function. If options should be retrieved from krb5.conf, call
* putil_args_krb5() first, before calling this function.
*
* putil_args_defaults() should be called before this function.
*/
bool putil_args_parse(struct pam_args *, int argc, const char *argv[],
const struct option options[], size_t optlen)
__attribute__((__nonnull__));
/* Undo default visibility change. */
#pragma GCC visibility pop
END_DECLS
#endif /* !PAM_UTIL_OPTIONS_H */