2 * Copyright (c) 1997 - 1999, 2002 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include "krb5_locl.h"
36 #include "an2ln_plugin.h"
37 #include "db_plugin.h"
39 /* Default plugin (DB using binary search of sorted text file) follows */
40 static krb5_error_code KRB5_LIB_CALL an2ln_def_plug_init(krb5_context, void **);
41 static void KRB5_LIB_CALL an2ln_def_plug_fini(void *);
42 static krb5_error_code KRB5_LIB_CALL an2ln_def_plug_an2ln(void *, krb5_context, const char *,
43 krb5_const_principal, set_result_f,
46 static krb5plugin_an2ln_ftable an2ln_def_plug = {
53 /* Plugin engine code follows */
55 krb5_const_principal aname;
60 static krb5_error_code KRB5_LIB_CALL
61 set_res(void *userctx, const char *res)
63 struct plctx *plctx = userctx;
64 plctx->luser = heim_string_create(res);
65 if (plctx->luser == NULL)
70 static krb5_error_code KRB5_LIB_CALL
71 plcallback(krb5_context context,
72 const void *plug, void *plugctx, void *userctx)
74 const krb5plugin_an2ln_ftable *locate = plug;
75 struct plctx *plctx = userctx;
80 return locate->an2ln(plugctx, context, plctx->rule, plctx->aname, set_res, plctx);
83 static const char *an2ln_plugin_deps[] = { "krb5", NULL };
85 static struct heim_plugin_data
89 KRB5_PLUGIN_AN2LN_VERSION_0,
94 static krb5_error_code
95 an2ln_plugin(krb5_context context, const char *rule, krb5_const_principal aname,
96 size_t lnsize, char *lname)
106 * Order of plugin invocation is non-deterministic, but there should
107 * really be no more than one plugin that can handle any given kind
108 * rule, so the effect should be deterministic anyways.
110 ret = _krb5_plugin_run_f(context, &an2ln_plugin_data,
111 0, &ctx, plcallback);
113 heim_release(ctx.luser);
117 if (ctx.luser == NULL)
118 return KRB5_PLUGIN_NO_HANDLE;
120 if (strlcpy(lname, heim_string_get_utf8(ctx.luser), lnsize) >= lnsize)
121 ret = KRB5_CONFIG_NOTENUFSPACE;
123 heim_release(ctx.luser);
128 reg_def_plugins_once(void *ctx)
130 krb5_context context = ctx;
132 krb5_plugin_register(context, PLUGIN_TYPE_DATA, KRB5_PLUGIN_AN2LN,
137 princ_realm_is_default(krb5_context context,
138 krb5_const_principal aname)
141 krb5_realm *lrealms = NULL;
145 ret = krb5_get_default_realms(context, &lrealms);
150 for (r = lrealms; *r != NULL; ++r) {
151 if (strcmp (*r, aname->realm) == 0) {
156 krb5_free_host_realm (context, lrealms);
161 * This function implements MIT's auth_to_local_names configuration for
162 * configuration compatibility. Specifically:
166 * auth_to_local_names = {
167 * <unparsed-principal-name> = <username>
171 * If multiple usernames are configured then the last one is taken.
173 * The configuration can only be expected to hold a relatively small
174 * number of mappings. For lots of mappings use a DB.
176 static krb5_error_code
177 an2ln_local_names(krb5_context context,
178 krb5_const_principal aname,
188 if (!princ_realm_is_default(context, aname))
189 return KRB5_PLUGIN_NO_HANDLE;
191 ret = krb5_unparse_name_flags(context, aname,
192 KRB5_PRINCIPAL_UNPARSE_NO_REALM,
197 ret = KRB5_PLUGIN_NO_HANDLE;
198 values = krb5_config_get_strings(context, NULL, "realms", aname->realm,
199 "auth_to_local_names", unparsed, NULL);
203 /* Take the last value, just like MIT */
204 for (res = NULL, i = 0; values[i]; i++)
208 if (strlcpy(lname, res, lnsize) >= lnsize)
209 ret = KRB5_CONFIG_NOTENUFSPACE;
211 if (!*res || strcmp(res, ":") == 0)
212 ret = KRB5_NO_LOCALNAME;
215 krb5_config_free_strings(values);
220 * Heimdal's default aname2lname mapping.
222 static krb5_error_code
223 an2ln_default(krb5_context context,
225 krb5_const_principal aname,
226 size_t lnsize, char *lname)
232 if (strcmp(rule, "NONE") == 0)
233 return KRB5_NO_LOCALNAME;
235 if (strcmp(rule, "DEFAULT") == 0)
237 else if (strcmp(rule, "HEIMDAL_DEFAULT") == 0)
240 return KRB5_PLUGIN_NO_HANDLE;
242 if (!princ_realm_is_default(context, aname))
243 return KRB5_PLUGIN_NO_HANDLE;
245 if (aname->name.name_string.len == 1) {
247 * One component principal names in default realm -> the one
248 * component is the username.
250 res = aname->name.name_string.val[0];
251 } else if (root_princs_ok && aname->name.name_string.len == 2 &&
252 strcmp (aname->name.name_string.val[1], "root") == 0) {
254 * Two-component principal names in default realm where the
255 * first component is "root" -> root IFF the principal is in
256 * root's .k5login (or whatever krb5_kuserok() does).
258 krb5_principal rootprinc;
263 ret = krb5_copy_principal(context, aname, &rootprinc);
267 userok = _krb5_kuserok(context, rootprinc, res, FALSE);
268 krb5_free_principal(context, rootprinc);
270 return KRB5_NO_LOCALNAME;
272 return KRB5_PLUGIN_NO_HANDLE;
275 if (strlcpy(lname, res, lnsize) >= lnsize)
276 return KRB5_CONFIG_NOTENUFSPACE;
282 * Map a principal name to a local username.
284 * Returns 0 on success, KRB5_NO_LOCALNAME if no mapping was found, or
285 * some Kerberos or system error.
289 * @param context A krb5_context
290 * @param aname A principal name
291 * @param lnsize The size of the buffer into which the username will be written
292 * @param lname The buffer into which the username will be written
294 * @ingroup krb5_support
296 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
297 krb5_aname_to_localname(krb5_context context,
298 krb5_const_principal aname,
302 static heim_base_once_t reg_def_plugins = HEIM_BASE_ONCE_INIT;
312 heim_base_once_f(®_def_plugins, context, reg_def_plugins_once);
314 /* Try MIT's auth_to_local_names config first */
315 ret = an2ln_local_names(context, aname, lnsize, lname);
316 if (ret != KRB5_PLUGIN_NO_HANDLE)
319 ret = krb5_get_default_realm(context, &realm);
323 rules = krb5_config_get_strings(context, NULL, "realms", realm,
324 "auth_to_local", NULL);
327 /* Heimdal's default rule */
328 ret = an2ln_default(context, "HEIMDAL_DEFAULT", aname, lnsize, lname);
329 if (ret == KRB5_PLUGIN_NO_HANDLE)
330 return KRB5_NO_LOCALNAME;
337 * Note that RULEs and DBs only have white-list functionality,
338 * thus RULEs and DBs that we don't understand we simply ignore.
340 * This means that plugins that implement black-lists are
341 * dangerous: if a black-list plugin isn't found, the black-list
342 * won't be enforced. But black-lists are dangerous anyways.
344 for (ret = KRB5_PLUGIN_NO_HANDLE, i = 0; rules[i]; i++) {
347 /* Try NONE, DEFAULT, and HEIMDAL_DEFAULT rules */
348 ret = an2ln_default(context, rule, aname, lnsize, lname);
349 if (ret == KRB5_PLUGIN_NO_HANDLE)
350 /* Try DB, RULE, ... plugins */
351 ret = an2ln_plugin(context, rule, aname, lnsize, lname);
353 if (ret == 0 && lnsize && !lname[0])
354 continue; /* Success but no lname?! lies! */
355 else if (ret != KRB5_PLUGIN_NO_HANDLE)
359 if (ret == KRB5_PLUGIN_NO_HANDLE) {
362 ret = KRB5_NO_LOCALNAME;
365 krb5_config_free_strings(rules);
369 static krb5_error_code KRB5_LIB_CALL
370 an2ln_def_plug_init(krb5_context context, void **ctx)
376 static void KRB5_LIB_CALL
377 an2ln_def_plug_fini(void *ctx)
381 static heim_base_once_t sorted_text_db_init_once = HEIM_BASE_ONCE_INIT;
384 sorted_text_db_init_f(void *arg)
386 (void) heim_db_register("sorted-text", NULL, &heim_sorted_text_file_dbtype);
389 static krb5_error_code KRB5_LIB_CALL
390 an2ln_def_plug_an2ln(void *plug_ctx, krb5_context context,
392 krb5_const_principal aname,
393 set_result_f set_res_f, void *set_res_ctx)
396 const char *an2ln_db_fname;
397 heim_db_t dbh = NULL;
398 heim_dict_t db_options;
401 char *unparsed = NULL;
404 _krb5_load_db_plugins(context);
405 heim_base_once_f(&sorted_text_db_init_once, NULL, sorted_text_db_init_f);
407 if (strncmp(rule, "DB:", strlen("DB:")) != 0)
408 return KRB5_PLUGIN_NO_HANDLE;
410 an2ln_db_fname = &rule[strlen("DB:")];
411 if (!*an2ln_db_fname)
412 return KRB5_PLUGIN_NO_HANDLE;
414 ret = krb5_unparse_name(context, aname, &unparsed);
418 db_options = heim_dict_create(11);
419 if (db_options != NULL)
420 heim_dict_set_value(db_options, HSTR("read-only"),
421 heim_number_create(1));
422 dbh = heim_db_create(NULL, an2ln_db_fname, db_options, &error);
424 krb5_set_error_message(context, heim_error_get_code(error),
425 N_("Couldn't open aname2lname-text-db", ""));
426 ret = KRB5_PLUGIN_NO_HANDLE;
430 /* Binary search; file should be sorted (in C locale) */
431 k = heim_data_ref_create(unparsed, strlen(unparsed), NULL);
433 ret = krb5_enomem(context);
436 v = heim_db_copy_value(dbh, NULL, k, &error);
438 if (v == NULL && error != NULL) {
439 krb5_set_error_message(context, heim_error_get_code(error),
440 N_("Lookup in aname2lname-text-db failed", ""));
441 ret = heim_error_get_code(error);
443 } else if (v == NULL) {
444 ret = KRB5_PLUGIN_NO_HANDLE;
448 if (heim_data_get_length(v) == 0) {
449 krb5_set_error_message(context, ret,
450 N_("Principal mapped to empty username", ""));
451 ret = KRB5_NO_LOCALNAME;
454 value = strndup(heim_data_get_ptr(v), heim_data_get_length(v));
457 ret = krb5_enomem(context);
460 ret = set_res_f(set_res_ctx, value);