1*bf6873c5SCy Schubert /* 2*bf6873c5SCy Schubert * Interface to PAM option parsing. 3*bf6873c5SCy Schubert * 4*bf6873c5SCy Schubert * This interface defines a lot of macros and types with very short names, and 5*bf6873c5SCy Schubert * hence without a lot of namespace protection. It should be included only in 6*bf6873c5SCy Schubert * the file that's doing the option parsing and not elsewhere to remove the 7*bf6873c5SCy Schubert * risk of clashes. 8*bf6873c5SCy Schubert * 9*bf6873c5SCy Schubert * The canonical version of this file is maintained in the rra-c-util package, 10*bf6873c5SCy Schubert * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>. 11*bf6873c5SCy Schubert * 12*bf6873c5SCy Schubert * Written by Russ Allbery <eagle@eyrie.org> 13*bf6873c5SCy Schubert * Copyright 2020 Russ Allbery <eagle@eyrie.org> 14*bf6873c5SCy Schubert * Copyright 2010-2011, 2013 15*bf6873c5SCy Schubert * The Board of Trustees of the Leland Stanford Junior University 16*bf6873c5SCy Schubert * 17*bf6873c5SCy Schubert * Permission is hereby granted, free of charge, to any person obtaining a 18*bf6873c5SCy Schubert * copy of this software and associated documentation files (the "Software"), 19*bf6873c5SCy Schubert * to deal in the Software without restriction, including without limitation 20*bf6873c5SCy Schubert * the rights to use, copy, modify, merge, publish, distribute, sublicense, 21*bf6873c5SCy Schubert * and/or sell copies of the Software, and to permit persons to whom the 22*bf6873c5SCy Schubert * Software is furnished to do so, subject to the following conditions: 23*bf6873c5SCy Schubert * 24*bf6873c5SCy Schubert * The above copyright notice and this permission notice shall be included in 25*bf6873c5SCy Schubert * all copies or substantial portions of the Software. 26*bf6873c5SCy Schubert * 27*bf6873c5SCy Schubert * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28*bf6873c5SCy Schubert * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29*bf6873c5SCy Schubert * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30*bf6873c5SCy Schubert * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31*bf6873c5SCy Schubert * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32*bf6873c5SCy Schubert * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 33*bf6873c5SCy Schubert * DEALINGS IN THE SOFTWARE. 34*bf6873c5SCy Schubert * 35*bf6873c5SCy Schubert * SPDX-License-Identifier: MIT 36*bf6873c5SCy Schubert */ 37*bf6873c5SCy Schubert 38*bf6873c5SCy Schubert #ifndef PAM_UTIL_OPTIONS_H 39*bf6873c5SCy Schubert #define PAM_UTIL_OPTIONS_H 1 40*bf6873c5SCy Schubert 41*bf6873c5SCy Schubert #include <config.h> 42*bf6873c5SCy Schubert #ifdef HAVE_KRB5 43*bf6873c5SCy Schubert # include <portable/krb5.h> 44*bf6873c5SCy Schubert #endif 45*bf6873c5SCy Schubert #include <portable/macros.h> 46*bf6873c5SCy Schubert #include <portable/stdbool.h> 47*bf6873c5SCy Schubert 48*bf6873c5SCy Schubert #include <stddef.h> 49*bf6873c5SCy Schubert 50*bf6873c5SCy Schubert /* Forward declarations to avoid additional includes. */ 51*bf6873c5SCy Schubert struct vector; 52*bf6873c5SCy Schubert 53*bf6873c5SCy Schubert /* 54*bf6873c5SCy Schubert * The types of configuration values possible. STRLIST is a list data type 55*bf6873c5SCy Schubert * that takes its default from a string value instead of a vector. For 56*bf6873c5SCy Schubert * STRLIST, the default string value will be turned into a vector by splitting 57*bf6873c5SCy Schubert * on comma, space, and tab. (This is the same as would be done with the 58*bf6873c5SCy Schubert * value of a PAM setting when the target variable type is a list.) 59*bf6873c5SCy Schubert */ 60*bf6873c5SCy Schubert enum type 61*bf6873c5SCy Schubert { 62*bf6873c5SCy Schubert TYPE_BOOLEAN, 63*bf6873c5SCy Schubert TYPE_NUMBER, 64*bf6873c5SCy Schubert TYPE_TIME, 65*bf6873c5SCy Schubert TYPE_STRING, 66*bf6873c5SCy Schubert TYPE_LIST, 67*bf6873c5SCy Schubert TYPE_STRLIST 68*bf6873c5SCy Schubert }; 69*bf6873c5SCy Schubert 70*bf6873c5SCy Schubert /* 71*bf6873c5SCy Schubert * Each configuration option is defined by a struct option. This specifies 72*bf6873c5SCy Schubert * the name of the option, its offset into the configuration struct, whether 73*bf6873c5SCy Schubert * it can be specified in a krb5.conf file, its type, and its default value if 74*bf6873c5SCy Schubert * not set. Note that PAM configuration options are specified as strings, so 75*bf6873c5SCy Schubert * there's no native way of representing a list argument. List values are 76*bf6873c5SCy Schubert * always initialized by splitting a string on whitespace or commas. 77*bf6873c5SCy Schubert * 78*bf6873c5SCy Schubert * The default value should really be a union, but you can't initialize unions 79*bf6873c5SCy Schubert * properly in C in a static initializer without C99 named initializer 80*bf6873c5SCy Schubert * support, which we can't (yet) assume. So use a struct instead, and 81*bf6873c5SCy Schubert * initialize all the members, even though we'll only care about one of them. 82*bf6873c5SCy Schubert * 83*bf6873c5SCy Schubert * Note that numbers set in the configuration struct created by this interface 84*bf6873c5SCy Schubert * must be longs, not ints. There is currently no provision for unsigned 85*bf6873c5SCy Schubert * numbers. 86*bf6873c5SCy Schubert * 87*bf6873c5SCy Schubert * Times take their default from defaults.number. The difference between time 88*bf6873c5SCy Schubert * and number is in the parsing of a user-supplied value and the type of the 89*bf6873c5SCy Schubert * stored attribute. 90*bf6873c5SCy Schubert */ 91*bf6873c5SCy Schubert struct option { 92*bf6873c5SCy Schubert const char *name; 93*bf6873c5SCy Schubert size_t location; 94*bf6873c5SCy Schubert bool krb5_config; 95*bf6873c5SCy Schubert enum type type; 96*bf6873c5SCy Schubert struct { 97*bf6873c5SCy Schubert bool boolean; 98*bf6873c5SCy Schubert long number; 99*bf6873c5SCy Schubert const char *string; 100*bf6873c5SCy Schubert const struct vector *list; 101*bf6873c5SCy Schubert } defaults; 102*bf6873c5SCy Schubert }; 103*bf6873c5SCy Schubert 104*bf6873c5SCy Schubert /* 105*bf6873c5SCy Schubert * The following macros are helpers to make it easier to define the table that 106*bf6873c5SCy Schubert * specifies how to convert the configuration into a struct. They provide an 107*bf6873c5SCy Schubert * initializer for the type and default fields. 108*bf6873c5SCy Schubert */ 109*bf6873c5SCy Schubert /* clang-format off */ 110*bf6873c5SCy Schubert #define BOOL(def) TYPE_BOOLEAN, { (def), 0, NULL, NULL } 111*bf6873c5SCy Schubert #define NUMBER(def) TYPE_NUMBER, { 0, (def), NULL, NULL } 112*bf6873c5SCy Schubert #define TIME(def) TYPE_TIME, { 0, (def), NULL, NULL } 113*bf6873c5SCy Schubert #define STRING(def) TYPE_STRING, { 0, 0, (def), NULL } 114*bf6873c5SCy Schubert #define LIST(def) TYPE_LIST, { 0, 0, NULL, (def) } 115*bf6873c5SCy Schubert #define STRLIST(def) TYPE_STRLIST, { 0, 0, (def), NULL } 116*bf6873c5SCy Schubert /* clang-format on */ 117*bf6873c5SCy Schubert 118*bf6873c5SCy Schubert /* 119*bf6873c5SCy Schubert * The user of this file should also define a macro of the following form: 120*bf6873c5SCy Schubert * 121*bf6873c5SCy Schubert * #define K(name) (#name), offsetof(struct pam_config, name) 122*bf6873c5SCy Schubert * 123*bf6873c5SCy Schubert * Then, the definition of the necessary table for building the configuration 124*bf6873c5SCy Schubert * will look something like this: 125*bf6873c5SCy Schubert * 126*bf6873c5SCy Schubert * const struct option options[] = { 127*bf6873c5SCy Schubert * { K(aklog_homedir), true, BOOL (false) }, 128*bf6873c5SCy Schubert * { K(cells), true, LIST (NULL) }, 129*bf6873c5SCy Schubert * { K(debug), false, BOOL (false) }, 130*bf6873c5SCy Schubert * { K(minimum_uid), true, NUMBER (0) }, 131*bf6873c5SCy Schubert * { K(program), true, STRING (NULL) }, 132*bf6873c5SCy Schubert * }; 133*bf6873c5SCy Schubert * 134*bf6873c5SCy Schubert * which provides a nice, succinct syntax for creating the table. The options 135*bf6873c5SCy Schubert * MUST be in sorted order, since the options parsing code does a binary 136*bf6873c5SCy Schubert * search. 137*bf6873c5SCy Schubert */ 138*bf6873c5SCy Schubert 139*bf6873c5SCy Schubert BEGIN_DECLS 140*bf6873c5SCy Schubert 141*bf6873c5SCy Schubert /* Default to a hidden visibility for all internal functions. */ 142*bf6873c5SCy Schubert #pragma GCC visibility push(hidden) 143*bf6873c5SCy Schubert 144*bf6873c5SCy Schubert /* 145*bf6873c5SCy Schubert * Set the defaults for the PAM configuration. Takes the PAM arguments, an 146*bf6873c5SCy Schubert * option table defined as above, and the number of entries in the table. The 147*bf6873c5SCy Schubert * config member of the args struct must already be allocated. Returns true 148*bf6873c5SCy Schubert * on success and false on error (generally out of memory). Errors will 149*bf6873c5SCy Schubert * already be reported using putil_crit(). 150*bf6873c5SCy Schubert * 151*bf6873c5SCy Schubert * This function must be called before either putil_args_krb5() or 152*bf6873c5SCy Schubert * putil_args_parse(), since neither of those functions set defaults. 153*bf6873c5SCy Schubert */ 154*bf6873c5SCy Schubert bool putil_args_defaults(struct pam_args *, const struct option options[], 155*bf6873c5SCy Schubert size_t optlen) __attribute__((__nonnull__)); 156*bf6873c5SCy Schubert 157*bf6873c5SCy Schubert /* 158*bf6873c5SCy Schubert * Fill out options from krb5.conf. Takes the PAM args structure, the name of 159*bf6873c5SCy Schubert * the section for the software being configured, an option table defined as 160*bf6873c5SCy Schubert * above, and the number of entries in the table. The config member of the 161*bf6873c5SCy Schubert * args struct must already be allocated. Only those options whose 162*bf6873c5SCy Schubert * krb5_config attribute is true will be considered. 163*bf6873c5SCy Schubert * 164*bf6873c5SCy Schubert * This code automatically checks for configuration settings scoped to the 165*bf6873c5SCy Schubert * local realm, so the default realm should be set before calling this 166*bf6873c5SCy Schubert * function. If that's done based on a configuration option, one may need to 167*bf6873c5SCy Schubert * pre-parse the configuration options. 168*bf6873c5SCy Schubert * 169*bf6873c5SCy Schubert * Returns true on success and false on an error. An error return should be 170*bf6873c5SCy Schubert * considered fatal. Errors will already be reported using putil_crit*() or 171*bf6873c5SCy Schubert * putil_err*() as appropriate. If Kerberos is not available, returns without 172*bf6873c5SCy Schubert * doing anything. 173*bf6873c5SCy Schubert * 174*bf6873c5SCy Schubert * putil_args_defaults() should be called before this function. 175*bf6873c5SCy Schubert */ 176*bf6873c5SCy Schubert bool putil_args_krb5(struct pam_args *, const char *section, 177*bf6873c5SCy Schubert const struct option options[], size_t optlen) 178*bf6873c5SCy Schubert __attribute__((__nonnull__)); 179*bf6873c5SCy Schubert 180*bf6873c5SCy Schubert /* 181*bf6873c5SCy Schubert * Parse the PAM arguments and fill out the provided struct. Takes the PAM 182*bf6873c5SCy Schubert * arguments, the argument count and vector, an option table defined as above, 183*bf6873c5SCy Schubert * and the number of entries in the table. The config member of the args 184*bf6873c5SCy Schubert * struct must already be allocated. Returns true on success and false on 185*bf6873c5SCy Schubert * error. An error return should be considered fatal. Errors will already be 186*bf6873c5SCy Schubert * reported using putil_crit(). Unknown options will also be diagnosed (to 187*bf6873c5SCy Schubert * syslog at LOG_ERR using putil_err()), but are not considered fatal errors 188*bf6873c5SCy Schubert * and will still return true. 189*bf6873c5SCy Schubert * 190*bf6873c5SCy Schubert * The krb5_config option of the option configuration is ignored by this 191*bf6873c5SCy Schubert * function. If options should be retrieved from krb5.conf, call 192*bf6873c5SCy Schubert * putil_args_krb5() first, before calling this function. 193*bf6873c5SCy Schubert * 194*bf6873c5SCy Schubert * putil_args_defaults() should be called before this function. 195*bf6873c5SCy Schubert */ 196*bf6873c5SCy Schubert bool putil_args_parse(struct pam_args *, int argc, const char *argv[], 197*bf6873c5SCy Schubert const struct option options[], size_t optlen) 198*bf6873c5SCy Schubert __attribute__((__nonnull__)); 199*bf6873c5SCy Schubert 200*bf6873c5SCy Schubert /* Undo default visibility change. */ 201*bf6873c5SCy Schubert #pragma GCC visibility pop 202*bf6873c5SCy Schubert 203*bf6873c5SCy Schubert END_DECLS 204*bf6873c5SCy Schubert 205*bf6873c5SCy Schubert #endif /* !PAM_UTIL_OPTIONS_H */ 206