2 * Retrieve configuration settings from krb5.conf.
4 * Provided here are functions to retrieve boolean, numeric, and string
5 * settings from krb5.conf. This wraps the somewhat awkward
6 * krb5_appdefaults_* functions.
8 * Written by Russ Allbery <eagle@eyrie.org>
10 * The Board of Trustees of the Leland Stanford Junior University
12 * See LICENSE for licensing terms.
16 #include <portable/krb5.h>
17 #include <portable/system.h>
21 #include <plugin/internal.h>
22 #include <util/macros.h>
24 /* The representation of the realm differs between MIT and Kerberos. */
25 #ifdef HAVE_KRB5_REALM
26 typedef krb5_realm realm_type;
28 typedef krb5_data *realm_type;
33 * Obtain the default realm and translate it into the format required by
34 * krb5_appdefault_*. This is obnoxious for MIT Kerberos, which returns the
35 * default realm as a string but expects the realm as a krb5_data type when
36 * calling krb5_appdefault_*.
38 #ifdef HAVE_KRB5_REALM
41 default_realm(krb5_context ctx)
46 code = krb5_get_default_realm(ctx, &realm);
52 #else /* !HAVE_KRB5_REALM */
55 default_realm(krb5_context ctx)
59 krb5_data *realm_data;
61 realm_data = calloc(1, sizeof(krb5_data));
62 if (realm_data == NULL)
64 code = krb5_get_default_realm(ctx, &realm);
69 realm_data->magic = KV5M_DATA;
70 realm_data->data = strdup(realm);
71 if (realm_data->data == NULL) {
73 krb5_free_default_realm(ctx, realm);
76 realm_data->length = strlen(realm);
77 krb5_free_default_realm(ctx, realm);
81 #endif /* !HAVE_KRB5_REALM */
85 * Free the default realm data in whatever form it was generated for the calls
86 * to krb5_appdefault_*.
88 #ifdef HAVE_KRB5_REALM
91 free_default_realm(krb5_context ctx UNUSED, realm_type realm)
93 krb5_free_default_realm(ctx, realm);
96 #else /* !HAVE_KRB5_REALM */
99 free_default_realm(krb5_context ctx UNUSED, realm_type realm)
105 #endif /* !HAVE_KRB5_REALM */
109 * Load a boolean option from Kerberos appdefaults. Takes the Kerberos
110 * context, the option, and the result location.
113 strength_config_boolean(krb5_context ctx, const char *opt, bool *result)
119 * The MIT version of krb5_appdefault_boolean takes an int * and the
120 * Heimdal version takes a krb5_boolean *, so hope that Heimdal always
121 * defines krb5_boolean to int or this will require more portability work.
123 realm = default_realm(ctx);
124 krb5_appdefault_boolean(ctx, "krb5-strength", realm, opt, *result, &tmp);
126 free_default_realm(ctx, realm);
131 * Parse a single class specification. Currently, this assumes that the class
132 * specification is a comma-separated list of required classes, and those
133 * classes are required for any length of password. This will be enhanced
136 static krb5_error_code
137 parse_class(krb5_context ctx, const char *spec, struct class_rule **rule)
139 struct vector *classes;
141 krb5_error_code code;
143 /* Parse the required classes into a vector. */
144 classes = strength_vector_split_multi(spec, ",", NULL);
146 return strength_error_system(ctx, "cannot allocate memory");
148 /* Create the basic rule structure. */
149 *rule = calloc(1, sizeof(struct class_rule));
154 * Walk the list of required classes and set our flags, diagnosing an
155 * unknown character class.
157 for (i = 0; i < classes->count; i++) {
158 if (strcmp(classes->strings[i], "upper") == 0)
159 (*rule)->upper = true;
160 else if (strcmp(classes->strings[i], "lower") == 0)
161 (*rule)->lower = true;
162 else if (strcmp(classes->strings[i], "digit") == 0)
163 (*rule)->digit = true;
164 else if (strcmp(classes->strings[i], "symbol") == 0)
165 (*rule)->symbol = true;
167 code = strength_error_config(ctx, "unknown character class %s",
168 classes->strings[i]);
169 strength_vector_free(classes);
175 strength_vector_free(classes);
181 * Parse character class requirements from Kerberos appdefaults. Takes the
182 * Kerberos context, the option, and the place to store the linked list of
183 * class requirements.
186 strength_config_classes(krb5_context ctx, const char *opt,
187 struct class_rule **result)
189 struct vector *config;
190 struct class_rule *rules, *last, *tmp;
191 krb5_error_code code;
194 /* Get the basic configuration as a list. */
195 code = strength_config_list(ctx, opt, &config);
198 if (config == NULL || config->count == 0) {
203 /* Each word in the list will be a class rule. */
204 code = parse_class(ctx, config->strings[0], &rules);
208 for (i = 1; i < config->count; i++) {
209 code = parse_class(ctx, config->strings[i], &last->next);
215 /* Success. Free the vector and return the results. */
216 strength_vector_free(config);
222 while (last != NULL) {
227 strength_vector_free(config);
233 * Load a list option from Kerberos appdefaults. Takes the Kerberos context,
234 * the option, and the result location. The option is read as a string and
235 * the split on spaces and tabs into a list.
237 * This requires an annoying workaround because one cannot specify a default
238 * value of NULL with MIT Kerberos, since MIT Kerberos unconditionally calls
239 * strdup on the default value. There's also no way to determine if memory
240 * allocation failed while parsing or while setting the default value.
243 strength_config_list(krb5_context ctx, const char *opt,
244 struct vector **result)
249 /* Obtain the string from [appdefaults]. */
250 realm = default_realm(ctx);
251 krb5_appdefault_string(ctx, "krb5-sync", realm, opt, "", &value);
252 free_default_realm(ctx, realm);
254 /* If we got something back, store it in result. */
256 if (value[0] != '\0') {
257 *result = strength_vector_split_multi(value, " \t", *result);
259 return strength_error_system(ctx, "cannot allocate memory");
261 krb5_free_string(ctx, value);
268 * Load a number option from Kerberos appdefaults. Takes the Kerberos
269 * context, the option, and the result location. The native interface doesn't
270 * support numbers, so we actually read a string and then convert.
273 strength_config_number(krb5_context ctx, const char *opt, long *result)
280 /* Obtain the setting in string form from [appdefaults]. */
281 realm = default_realm(ctx);
282 krb5_appdefault_string(ctx, "krb5-strength", realm, opt, "", &tmp);
283 free_default_realm(ctx, realm);
286 * If we found anything, convert it to a number. Currently, we ignore
289 if (tmp != NULL && tmp[0] != '\0') {
291 value = strtol(tmp, &end, 10);
292 if (errno == 0 && *end == '\0')
296 krb5_free_string(ctx, tmp);
301 * Load a string option from Kerberos appdefaults. Takes the Kerberos
302 * context, the option, and the result location.
304 * This requires an annoying workaround because one cannot specify a default
305 * value of NULL with MIT Kerberos, since MIT Kerberos unconditionally calls
306 * strdup on the default value. There's also no way to determine if memory
307 * allocation failed while parsing or while setting the default value, so we
308 * don't return an error code.
311 strength_config_string(krb5_context ctx, const char *opt, char **result)
316 /* Obtain the string from [appdefaults]. */
317 realm = default_realm(ctx);
318 krb5_appdefault_string(ctx, "krb5-strength", realm, opt, "", &value);
319 free_default_realm(ctx, realm);
321 /* If we got something back, store it in result. */
323 if (value[0] != '\0') {
325 *result = strdup(value);
327 krb5_free_string(ctx, value);