/* * 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 */