Make krb5_aname_to_localname() use the libheimbase binary search functions
This commit is contained in:
@@ -111,6 +111,7 @@ dist_libkrb5_la_SOURCES = \
|
|||||||
acl.c \
|
acl.c \
|
||||||
add_et_list.c \
|
add_et_list.c \
|
||||||
addr_families.c \
|
addr_families.c \
|
||||||
|
an2ln_plugin.h \
|
||||||
aname_to_localname.c \
|
aname_to_localname.c \
|
||||||
appdefault.c \
|
appdefault.c \
|
||||||
asn1_glue.c \
|
asn1_glue.c \
|
||||||
@@ -339,7 +340,7 @@ nodist_include_HEADERS = krb5_err.h heim_err.h k524_err.h
|
|||||||
|
|
||||||
# XXX use nobase_include_HEADERS = krb5/locate_plugin.h
|
# XXX use nobase_include_HEADERS = krb5/locate_plugin.h
|
||||||
krb5dir = $(includedir)/krb5
|
krb5dir = $(includedir)/krb5
|
||||||
krb5_HEADERS = locate_plugin.h send_to_kdc_plugin.h ccache_plugin.h
|
krb5_HEADERS = locate_plugin.h send_to_kdc_plugin.h ccache_plugin.h an2ln_plugin.h
|
||||||
|
|
||||||
build_HEADERZ = \
|
build_HEADERZ = \
|
||||||
$(krb5_HEADERS) \
|
$(krb5_HEADERS) \
|
||||||
|
53
lib/krb5/an2ln_plugin.h
Normal file
53
lib/krb5/an2ln_plugin.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006 Kungliga Tekniska Högskolan
|
||||||
|
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#ifndef HEIMDAL_KRB5_AN2LN_PLUGIN_H
|
||||||
|
#define HEIMDAL_KRB5_AN2LN_PLUGIN_H 1
|
||||||
|
|
||||||
|
#define KRB5_PLUGIN_AN2LN "an2ln"
|
||||||
|
#define KRB5_PLUGIN_AN2LN_VERSION_0 0
|
||||||
|
|
||||||
|
typedef krb5_error_code (*set_result_f)(void *, const char *);
|
||||||
|
|
||||||
|
typedef struct krb5plugin_an2ln_ftable_desc {
|
||||||
|
int minor_version;
|
||||||
|
krb5_error_code (*init)(krb5_context, void **);
|
||||||
|
void (*fini)(void *);
|
||||||
|
krb5_error_code (*an2ln)(void *, krb5_context, const char *,
|
||||||
|
krb5_const_principal, set_result_f, void *);
|
||||||
|
} krb5plugin_an2ln_ftable;
|
||||||
|
|
||||||
|
#endif /* HEIMDAL_KRB5_AN2LN_PLUGIN_H */
|
||||||
|
|
@@ -32,20 +32,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "krb5_locl.h"
|
#include "krb5_locl.h"
|
||||||
|
#include "an2ln_plugin.h"
|
||||||
|
|
||||||
#define KRB5_PLUGIN_AN2LN "an2ln"
|
/* Default plugin (DB using binary search of sorted text file) follows */
|
||||||
#define KRB5_PLUGIN_AN2LN_VERSION_0 0
|
|
||||||
|
|
||||||
typedef krb5_error_code (*set_result_f)(void *, const char *);
|
|
||||||
|
|
||||||
typedef struct krb5plugin_an2ln_ftable_desc {
|
|
||||||
int minor_version;
|
|
||||||
krb5_error_code (*init)(krb5_context, void **);
|
|
||||||
void (*fini)(void *);
|
|
||||||
krb5_error_code (*an2ln)(void *, krb5_context, krb5_const_principal, set_result_f, void *);
|
|
||||||
} krb5plugin_an2ln_ftable;
|
|
||||||
|
|
||||||
/* Default plugin follows */
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
an2ln_def_plug_init(krb5_context context, void **ctx)
|
an2ln_def_plug_init(krb5_context context, void **ctx)
|
||||||
{
|
{
|
||||||
@@ -58,164 +47,75 @@ an2ln_def_plug_fini(void *ctx)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find a non-quoted new-line */
|
|
||||||
static char *
|
|
||||||
find_line(char *buf, size_t i, size_t right)
|
|
||||||
{
|
|
||||||
for (; i < right; i++) {
|
|
||||||
/* Seek a two non-quote char sequence */
|
|
||||||
if (buf[i] != '\\' && (i + 1) < right && buf[i + 1] != '\\') {
|
|
||||||
/* Seek a non-quoted new-line */
|
|
||||||
for (i += 1; i < right; i++) {
|
|
||||||
if (buf[i] == '\n')
|
|
||||||
break;
|
|
||||||
if (buf[i] == '\\' && (i + 1) < right && buf[i + 1] != '\n')
|
|
||||||
i++; /* skip quoted char */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf[i] == '\n' && (i + 1) < right)
|
|
||||||
return &buf[i + 1];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
an2ln_def_plug_an2ln(void *plug_ctx, krb5_context context,
|
an2ln_def_plug_an2ln(void *plug_ctx, krb5_context context,
|
||||||
krb5_const_principal princ,
|
const char *rule,
|
||||||
|
krb5_const_principal aname,
|
||||||
set_result_f set_res_f, void *set_res_ctx)
|
set_result_f set_res_f, void *set_res_ctx)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
const char *an2ln_db_fname;
|
const char *an2ln_db_fname;
|
||||||
char *fdata = NULL;
|
const char *ext;
|
||||||
|
bsearch_file_handle bfh = NULL;
|
||||||
char *unparsed = NULL;
|
char *unparsed = NULL;
|
||||||
char *cp;
|
char *value = NULL;
|
||||||
char *p;
|
|
||||||
char *u;
|
|
||||||
int fd = -1;
|
|
||||||
int cmp;
|
|
||||||
size_t sz, l, r, i, k;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
an2ln_db_fname = krb5_config_get_string(context, NULL, "libdefaults",
|
if (strncmp(rule, "DB:", strlen("DB:") != 0))
|
||||||
"aname2lname-text-db", NULL);
|
|
||||||
if (an2ln_db_fname)
|
|
||||||
return KRB5_PLUGIN_NO_HANDLE;
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
|
||||||
ret = krb5_unparse_name(context, princ, &unparsed);
|
/*
|
||||||
|
* This plugin implements a binary search of a sorted text file
|
||||||
|
* (sorted in the C locale). We really need to know that the file
|
||||||
|
* is text, so we implement a trivial heuristic: the file name must
|
||||||
|
* end in .txt.
|
||||||
|
*/
|
||||||
|
an2ln_db_fname = &rule[strlen("DB:")];
|
||||||
|
if (!*an2ln_db_fname)
|
||||||
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
if (strlen(an2ln_db_fname) < (strlen(".txt") + 1))
|
||||||
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
ext = strrchr(an2ln_db_fname, '.');
|
||||||
|
if (!ext || strcmp(ext, ".txt") != 0)
|
||||||
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
|
||||||
|
ret = krb5_unparse_name(context, aname, &unparsed);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fd = open(an2ln_db_fname, O_RDONLY);
|
ret = __bsearch_file_open(an2ln_db_fname, 0, 0, &bfh, NULL);
|
||||||
if (fd == -1) {
|
if (ret) {
|
||||||
|
krb5_set_error_message(context, ret,
|
||||||
|
N_("Couldn't open aname2lname-text-db", ""));
|
||||||
ret = KRB5_PLUGIN_NO_HANDLE;
|
ret = KRB5_PLUGIN_NO_HANDLE;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fstat(fd, &st) == -1 || st.st_size == 0) {
|
/* Binary search; file should be sorted (in C locale) */
|
||||||
|
ret = __bsearch_file(bfh, unparsed, &value, NULL, NULL, NULL);
|
||||||
|
if (ret > 0) {
|
||||||
|
krb5_set_error_message(context, ret,
|
||||||
|
N_("Couldn't map principal name to username", ""));
|
||||||
ret = KRB5_PLUGIN_NO_HANDLE;
|
ret = KRB5_PLUGIN_NO_HANDLE;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
} else if (ret < 0) {
|
||||||
|
ret = KRB5_PLUGIN_NO_HANDLE;
|
||||||
/*
|
|
||||||
* This is a dead-simple DB, so simple that we read the whole file
|
|
||||||
* in and do the search in memory. This means that in 32-bit
|
|
||||||
* processes we can't handle large files. But this should not be a
|
|
||||||
* large file anyways, else use another plugin.
|
|
||||||
*/
|
|
||||||
sz = (size_t)st.st_size;
|
|
||||||
if (st.st_size != (off_t)sz) {
|
|
||||||
ret = E2BIG;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
} else {
|
||||||
|
/* ret == 0 -> found */
|
||||||
fdata = malloc(sz + 1);
|
if (!value || !*value) {
|
||||||
if (fdata == NULL) {
|
krb5_set_error_message(context, ret,
|
||||||
ret = krb5_enomem(context);
|
N_("Principal mapped to empty username", ""));
|
||||||
goto cleanup;
|
ret = KRB5_NO_LOCALNAME;
|
||||||
}
|
goto cleanup;
|
||||||
if (read(fd, fdata, sz) < sz) {
|
|
||||||
krb5_set_error_message(context, errno, "read: reading aname2lname DB");
|
|
||||||
ret = errno;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
fdata[sz] = '\0';
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
|
|
||||||
/* Binary search; file should be sorted */
|
|
||||||
for (l = 0, r = sz, i = sz >> 1; i > l && i < r; ) {
|
|
||||||
heim_assert(i > 0 && i < sz, "invalid aname2lname db index");
|
|
||||||
|
|
||||||
/* fdata[i] is likely in the middle of a line; find the next line */
|
|
||||||
cp = find_line(fdata, i, r);
|
|
||||||
if (cp == NULL) {
|
|
||||||
/*
|
|
||||||
* No new line found to the right; search to the left then
|
|
||||||
* (this isn't optimal, but it's simple)
|
|
||||||
*/
|
|
||||||
r = i;
|
|
||||||
i = (r - l) >> 1;
|
|
||||||
}
|
|
||||||
i = cp - fdata;
|
|
||||||
heim_assert(i > l && i < r, "invalid aname2lname db index");
|
|
||||||
|
|
||||||
/* Got a line; check it */
|
|
||||||
|
|
||||||
/* Search for and split on unquoted whitespace */
|
|
||||||
for (p = &fdata[i], u = NULL, k = i; k < r; k++) {
|
|
||||||
if (fdata[k] == '\\') {
|
|
||||||
k++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* The one concession to CRLF here */
|
|
||||||
if (fdata[k] == '\r' || fdata[k] == '\n') {
|
|
||||||
fdata[k] = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isspace(fdata[k])) {
|
|
||||||
fdata[k] = '\0';
|
|
||||||
for (; k < r; k++) {
|
|
||||||
if (fdata[k] == '\\') {
|
|
||||||
k++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (fdata[k] == '\n')
|
|
||||||
fdata[k] = '\0';
|
|
||||||
while (isspace(fdata[k]))
|
|
||||||
k++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
u = &fdata[k];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmp = strcmp(p, unparsed);
|
|
||||||
if (cmp < 0) {
|
|
||||||
/* search left */
|
|
||||||
r = i;
|
|
||||||
i = (r - l) >> 1;
|
|
||||||
} else if (cmp > 0) {
|
|
||||||
/* search right */
|
|
||||||
l = i;
|
|
||||||
i = (r - l) >> 1;
|
|
||||||
} else {
|
|
||||||
/* match! */
|
|
||||||
if (u == NULL)
|
|
||||||
ret = KRB5_NO_LOCALNAME;
|
|
||||||
else
|
|
||||||
ret = set_res_f(set_res_ctx, u);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
ret = set_res_f(set_res_ctx, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (fd != -1)
|
if (bfh)
|
||||||
close(fd);
|
__bsearch_file_close(&bfh);
|
||||||
free(unparsed);
|
free(unparsed);
|
||||||
free(fdata);
|
free(value);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,9 +126,11 @@ krb5plugin_an2ln_ftable an2ln_def_plug = {
|
|||||||
an2ln_def_plug_an2ln,
|
an2ln_def_plug_an2ln,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Plugin engine code follows */
|
||||||
struct plctx {
|
struct plctx {
|
||||||
krb5_const_principal aname;
|
krb5_const_principal aname;
|
||||||
heim_string_t luser;
|
heim_string_t luser;
|
||||||
|
const char *rule;
|
||||||
};
|
};
|
||||||
|
|
||||||
static krb5_error_code KRB5_LIB_CALL
|
static krb5_error_code KRB5_LIB_CALL
|
||||||
@@ -251,59 +153,64 @@ plcallback(krb5_context context,
|
|||||||
if (plctx->luser)
|
if (plctx->luser)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return locate->an2ln(plugctx, context, plctx->aname, set_res, plctx);
|
return locate->an2ln(plugctx, context, plctx->rule, plctx->aname, set_res, plctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code
|
static krb5_error_code
|
||||||
an2lnplugin(krb5_context context, krb5_const_principal aname, heim_string_t *ures)
|
an2ln_plugin(krb5_context context, const char *rule, krb5_const_principal aname,
|
||||||
|
size_t lnsize, char *lname)
|
||||||
{
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
struct plctx ctx;
|
struct plctx ctx;
|
||||||
|
|
||||||
|
ctx.rule = rule;
|
||||||
ctx.aname = aname;
|
ctx.aname = aname;
|
||||||
ctx.luser = NULL;
|
ctx.luser = NULL;
|
||||||
|
|
||||||
_krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_AN2LN,
|
/*
|
||||||
KRB5_PLUGIN_AN2LN_VERSION_0,
|
* Order of plugin invocation is non-deterministic, but there should
|
||||||
0, &ctx, plcallback);
|
* really be no more than one plugin that can handle any given kind
|
||||||
|
* rule, so the effect should be deterministic anyways.
|
||||||
|
*/
|
||||||
|
ret = _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_AN2LN,
|
||||||
|
KRB5_PLUGIN_AN2LN_VERSION_0, 0, &ctx, plcallback);
|
||||||
|
if (ret != 0) {
|
||||||
|
heim_release(ctx.luser);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx.luser == NULL)
|
if (ctx.luser == NULL)
|
||||||
return KRB5_NO_LOCALNAME;
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
|
||||||
*ures = ctx.luser;
|
if (strlcpy(lname, heim_string_get_utf8(ctx.luser), lnsize) >= lnsize)
|
||||||
|
ret = KRB5_CONFIG_NOTENUFSPACE;
|
||||||
|
|
||||||
|
heim_release(ctx.luser);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reg_def_plugins_once(void *ctx)
|
reg_def_plugins_once(void *ctx)
|
||||||
{
|
{
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_context context = ctx;
|
krb5_context context = ctx;
|
||||||
|
|
||||||
ret = krb5_plugin_register(context, PLUGIN_TYPE_FUNC,
|
ret = krb5_plugin_register(context, PLUGIN_TYPE_DATA,
|
||||||
KRB5_PLUGIN_AN2LN, &an2ln_def_plug);
|
KRB5_PLUGIN_AN2LN, &an2ln_def_plug);
|
||||||
}
|
}
|
||||||
|
|
||||||
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
static int
|
||||||
krb5_aname_to_localname (krb5_context context,
|
princ_realm_is_default(krb5_context context,
|
||||||
krb5_const_principal aname,
|
krb5_const_principal aname)
|
||||||
size_t lnsize,
|
|
||||||
char *lname)
|
|
||||||
{
|
{
|
||||||
static heim_base_once_t reg_def_plugins = HEIM_BASE_ONCE_INIT;
|
|
||||||
krb5_error_code ret;
|
krb5_error_code ret;
|
||||||
krb5_realm *lrealms, *r;
|
krb5_realm *lrealms = NULL;
|
||||||
heim_string_t ures = NULL;
|
krb5_realm *r;
|
||||||
int valid;
|
int valid;
|
||||||
size_t len;
|
|
||||||
const char *res;
|
|
||||||
|
|
||||||
heim_base_once_f(®_def_plugins, context, reg_def_plugins_once);
|
ret = krb5_get_default_realms(context, &lrealms);
|
||||||
|
|
||||||
ret = krb5_get_default_realms (context, &lrealms);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return 0;
|
||||||
|
|
||||||
valid = 0;
|
valid = 0;
|
||||||
for (r = lrealms; *r != NULL; ++r) {
|
for (r = lrealms; *r != NULL; ++r) {
|
||||||
@@ -313,13 +220,96 @@ krb5_aname_to_localname (krb5_context context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
krb5_free_host_realm (context, lrealms);
|
krb5_free_host_realm (context, lrealms);
|
||||||
if (valid == 0)
|
return valid;
|
||||||
return KRB5_NO_LOCALNAME;
|
}
|
||||||
|
|
||||||
if (aname->name.name_string.len == 1)
|
/*
|
||||||
|
* This function implements MIT's auth_to_local_names configuration for
|
||||||
|
* configuration compatibility. Specifically:
|
||||||
|
*
|
||||||
|
* [realms]
|
||||||
|
* <realm-name> = {
|
||||||
|
* auth_to_local_names = {
|
||||||
|
* <unparsed-principal-name> = <username>
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* If multiple usernames are configured then the last one is taken.
|
||||||
|
*
|
||||||
|
* The configuration can only be expected to hold a relatively small
|
||||||
|
* number of mappings. For lots of mappings use a DB.
|
||||||
|
*/
|
||||||
|
static krb5_error_code
|
||||||
|
an2ln_local_names(krb5_context context,
|
||||||
|
krb5_const_principal aname,
|
||||||
|
size_t lnsize,
|
||||||
|
char *lname)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
char *unparsed;
|
||||||
|
char **values;
|
||||||
|
char *res;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!princ_realm_is_default(context, aname))
|
||||||
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
|
||||||
|
ret = krb5_unparse_name_flags(context, aname,
|
||||||
|
KRB5_PRINCIPAL_UNPARSE_NO_REALM,
|
||||||
|
&unparsed);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
values = krb5_config_get_strings(context, NULL, "realms", aname->realm,
|
||||||
|
"auth_to_local_names", unparsed, NULL);
|
||||||
|
free(unparsed);
|
||||||
|
if (!values)
|
||||||
|
return ret;
|
||||||
|
/* Take the last value, just like MIT */
|
||||||
|
for (res = NULL, i = 0; values[i]; i++)
|
||||||
|
res = values[i];
|
||||||
|
if (res) {
|
||||||
|
ret = 0;
|
||||||
|
if (strlcpy(lname, res, lnsize) >= lnsize)
|
||||||
|
ret = KRB5_CONFIG_NOTENUFSPACE;
|
||||||
|
|
||||||
|
if (!*res || strcmp(res, ":") == 0)
|
||||||
|
ret = KRB5_NO_LOCALNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_config_free_strings(values);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Heimdal's default aname2lname mapping.
|
||||||
|
*/
|
||||||
|
static krb5_error_code
|
||||||
|
an2ln_default(krb5_context context,
|
||||||
|
int root_princs_ok,
|
||||||
|
krb5_const_principal aname,
|
||||||
|
size_t lnsize, char *lname)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
const char *res;
|
||||||
|
|
||||||
|
if (!princ_realm_is_default(context, aname))
|
||||||
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
|
||||||
|
if (aname->name.name_string.len == 1) {
|
||||||
|
/*
|
||||||
|
* One component principal names in default realm -> the one
|
||||||
|
* component is the username.
|
||||||
|
*/
|
||||||
res = aname->name.name_string.val[0];
|
res = aname->name.name_string.val[0];
|
||||||
else if (aname->name.name_string.len == 2
|
} else if (aname->name.name_string.len == 2 &&
|
||||||
&& strcmp (aname->name.name_string.val[1], "root") == 0) {
|
strcmp (aname->name.name_string.val[1], "root") == 0) {
|
||||||
|
/*
|
||||||
|
* Two-component principal names in default realm where the
|
||||||
|
* first component is "root" -> root IFF the principal is in
|
||||||
|
* root's .k5login (or whatever krb5_kuserok() does).
|
||||||
|
*/
|
||||||
krb5_principal rootprinc;
|
krb5_principal rootprinc;
|
||||||
krb5_boolean userok;
|
krb5_boolean userok;
|
||||||
|
|
||||||
@@ -333,21 +323,91 @@ krb5_aname_to_localname (krb5_context context,
|
|||||||
krb5_free_principal(context, rootprinc);
|
krb5_free_principal(context, rootprinc);
|
||||||
if (!userok)
|
if (!userok)
|
||||||
return KRB5_NO_LOCALNAME;
|
return KRB5_NO_LOCALNAME;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ret = an2lnplugin(context, aname, &ures);
|
return KRB5_PLUGIN_NO_HANDLE;
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
res = heim_string_get_utf8(ures);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
len = strlen (res);
|
if (strlcpy(lname, res, lnsize) >= lnsize)
|
||||||
if (len >= lnsize)
|
return KRB5_CONFIG_NOTENUFSPACE;
|
||||||
return ERANGE;
|
|
||||||
strlcpy (lname, res, lnsize);
|
|
||||||
|
|
||||||
if (ures)
|
|
||||||
heim_release(ures);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map a principal name to a local username.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, KRB5_NO_LOCALNAME if no mapping was found, or
|
||||||
|
* some Kerberos or system error.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
*
|
||||||
|
* @context A krb5_context
|
||||||
|
* @aname A principal name
|
||||||
|
* @lnsize The size of the buffer into which the username will be written
|
||||||
|
* @lname The buffer into which the username will be written
|
||||||
|
*/
|
||||||
|
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||||
|
krb5_aname_to_localname(krb5_context context,
|
||||||
|
krb5_const_principal aname,
|
||||||
|
size_t lnsize,
|
||||||
|
char *lname)
|
||||||
|
{
|
||||||
|
static heim_base_once_t reg_def_plugins = HEIM_BASE_ONCE_INIT;
|
||||||
|
krb5_error_code ret;
|
||||||
|
size_t i;
|
||||||
|
char **rules = NULL;
|
||||||
|
char *rule;
|
||||||
|
|
||||||
|
if (lnsize)
|
||||||
|
lname[0] = '\0';
|
||||||
|
|
||||||
|
heim_base_once_f(®_def_plugins, context, reg_def_plugins_once);
|
||||||
|
|
||||||
|
/* Try MIT's auth_to_local_names config first */
|
||||||
|
ret = an2ln_local_names(context, aname, lnsize, lname);
|
||||||
|
if (ret != KRB5_PLUGIN_NO_HANDLE)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
rules = krb5_config_get_strings(context, NULL, "realms", aname->realm,
|
||||||
|
"auth_to_local", NULL);
|
||||||
|
if (!rules) {
|
||||||
|
/* Heimdal's default rule */
|
||||||
|
ret = an2ln_default(context, 1, aname, lnsize, lname);
|
||||||
|
if (ret == KRB5_PLUGIN_NO_HANDLE)
|
||||||
|
return KRB5_NO_LOCALNAME;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MIT rules */
|
||||||
|
for (ret = KRB5_PLUGIN_NO_HANDLE, i = 0; rules[i]; i++) {
|
||||||
|
rule = rules[i];
|
||||||
|
if (!*rule || strcmp(rule, "NONE") == 0)
|
||||||
|
break;
|
||||||
|
else if (strcmp(rule, "HEIMDAL_DEFAULT") == 0)
|
||||||
|
ret = an2ln_default(context, 1, aname, lnsize, lname);
|
||||||
|
else if (strcmp(rule, "DEFAULT") == 0)
|
||||||
|
ret = an2ln_default(context, 0, aname, lnsize, lname);
|
||||||
|
else
|
||||||
|
/* Let the plugins handle DBs and RULEs and anything else*/
|
||||||
|
ret = an2ln_plugin(context, rule, aname, lnsize, lname);
|
||||||
|
|
||||||
|
if (ret == 0 && lnsize && lname[0])
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* Note that RULEs and DBs only have white-list functionality,
|
||||||
|
* thus RULEs and DBs that we don't understand we simply ignore.
|
||||||
|
*
|
||||||
|
* This means that plugins that implement black-lists are
|
||||||
|
* dangerous: if a black-list plugin isn't found, the black-list
|
||||||
|
* won't be enforced. But black-lists are dangerous anyways.
|
||||||
|
*/
|
||||||
|
if (ret != KRB5_PLUGIN_NO_HANDLE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == KRB5_PLUGIN_NO_HANDLE)
|
||||||
|
ret = KRB5_NO_LOCALNAME;
|
||||||
|
|
||||||
|
krb5_config_free_strings(rules);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -269,8 +269,6 @@ given principal name, and if found the given username will be used, or,
|
|||||||
if the username is missing, an error will be returned. If the file
|
if the username is missing, an error will be returned. If the file
|
||||||
doesn't exist, or if no matching line is found then other plugins will
|
doesn't exist, or if no matching line is found then other plugins will
|
||||||
be allowed to run. Note: large
|
be allowed to run. Note: large
|
||||||
.Va aname2lname-text-db
|
|
||||||
files are not supported on small memory systems/processes.
|
|
||||||
.It Li name_canon_rules = Va rules
|
.It Li name_canon_rules = Va rules
|
||||||
One or more name canonicalization rules. Each rule consists of one or
|
One or more name canonicalization rules. Each rule consists of one or
|
||||||
more tokens separated by colon (':'). The first token must be a rule
|
more tokens separated by colon (':'). The first token must be a rule
|
||||||
@@ -363,6 +361,62 @@ See
|
|||||||
.It Li tgs_require_subkey
|
.It Li tgs_require_subkey
|
||||||
a boolan variable that defaults to false.
|
a boolan variable that defaults to false.
|
||||||
Old DCE secd (pre 1.1) might need this to be true.
|
Old DCE secd (pre 1.1) might need this to be true.
|
||||||
|
.It Li auth_to_local_names = {
|
||||||
|
.Bl -tag -width "xxx" -offset indent
|
||||||
|
.It Va principal_name = Va username
|
||||||
|
The given
|
||||||
|
.Va principal_name
|
||||||
|
will be mapped to the given
|
||||||
|
.Va username
|
||||||
|
if the
|
||||||
|
.Va REALM
|
||||||
|
is a default realm.
|
||||||
|
.El
|
||||||
|
.It Li }
|
||||||
|
.It Li auth_to_local = HEIMDAL_DEFAULT
|
||||||
|
Use the Heimdal default principal to username mapping.
|
||||||
|
Applies to principals from the
|
||||||
|
.Va REALM
|
||||||
|
if and only if
|
||||||
|
.Va REALM
|
||||||
|
is a default realm.
|
||||||
|
.It Li auth_to_local = DEFAULT
|
||||||
|
Use the MIT default principal to username mapping.
|
||||||
|
Applies to principals from the
|
||||||
|
.Va REALM
|
||||||
|
if and only if
|
||||||
|
.Va REALM
|
||||||
|
is a default realm.
|
||||||
|
.It Li auth_to_local = DB:/path/to/db.txt
|
||||||
|
Use a binary search of the given DB. The DB must be a flat-text
|
||||||
|
file sortedf in the "C" locale, with each record being a line
|
||||||
|
(separated by either LF or CRLF) consisting of a principal name
|
||||||
|
followed by whitespace followed by a username.
|
||||||
|
Applies to principals from the
|
||||||
|
.Va REALM
|
||||||
|
if and only if
|
||||||
|
.Va REALM
|
||||||
|
is a default realm.
|
||||||
|
.It Li auth_to_local = DB:/path/to/db
|
||||||
|
Use the given DB, if there's a plugin for it.
|
||||||
|
Applies to principals from the
|
||||||
|
.Va REALM
|
||||||
|
if and only if
|
||||||
|
.Va REALM
|
||||||
|
is a default realm.
|
||||||
|
.It Li auth_to_local = RULE:...
|
||||||
|
Use the given rule, if there's a plugin for it.
|
||||||
|
Applies to principals from the
|
||||||
|
.Va REALM
|
||||||
|
if and only if
|
||||||
|
.Va REALM
|
||||||
|
is a default realm.
|
||||||
|
.It Li auth_to_local = NONE
|
||||||
|
No additional principal to username mapping is done. Note that
|
||||||
|
.Va auth_to_local_names
|
||||||
|
and any preceding
|
||||||
|
.Va auth_to_local
|
||||||
|
rules have precedence.
|
||||||
.El
|
.El
|
||||||
.It Li }
|
.It Li }
|
||||||
.El
|
.El
|
||||||
|
Reference in New Issue
Block a user