krb5_utils.c revision 04c49a183f49c28f9ef900bdbc4eb30f23278e17
/*
SSSD
Kerberos 5 Backend Module -- Utilities
Authors:
Sumit Bose <sbose@redhat.com>
Copyright (C) 2009 Red Hat
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdlib.h>
#include <libgen.h>
#include "providers/krb5/krb5_utils.h"
#include "providers/krb5/krb5_auth.h"
#include "src/util/find_uid.h"
{
const char *upn;
int ret;
return ret;
}
} else {
return ENOMEM;
}
}
return EOK;
}
struct sss_domain_info *domain,
const char *user,
const char *upn)
{
int ret;
int sret;
struct sysdb_attrs *new_attrs;
struct ldb_result *res;
bool in_transaction = false;
const char *cached_upn;
return EINVAL;
}
return ENOMEM;
}
goto done;
}
goto done;
}
"nothing to do.\n"));
goto done;
}
goto done;
}
goto done;
}
goto done;
}
in_transaction = true;
goto done;
}
goto done;
}
in_transaction = false;
done:
if (in_transaction) {
}
}
return ret;
}
#define S_EXP_UID "{uid}"
#define S_EXP_USERID "{USERID}"
#define S_EXP_EUID "{euid}"
#define S_EXP_USERNAME "{username}"
bool case_sensitive, bool *private_path)
{
char *copy;
char *p;
char *n;
char *dummy;
char *name;
const char *cache_dir_tmpl;
char action;
bool rerun;
*private_path = false;
return NULL;
}
goto done;
}
goto done;
}
p = copy;
*n = '\0';
n++;
if ( *n == '\0' ) {
goto done;
}
rerun = true;
action = *n;
while (rerun) {
rerun = false;
switch (action) {
case 'u':
"because user name is empty.\n"));
goto done;
}
if (!name) {
("sss_get_cased_name failed\n"));
goto done;
}
name);
if (!file_mode) *private_path = true;
break;
case 'U':
"because uid is invalid.\n"));
goto done;
}
if (!file_mode) *private_path = true;
break;
case 'p':
"because upn is empty.\n"));
goto done;
}
if (!file_mode) *private_path = true;
break;
case '%':
break;
case 'r':
goto done;
}
break;
case 'h':
"because the path is not available.\n"));
goto done;
}
if (!file_mode) *private_path = true;
break;
case 'd':
if (file_mode) {
if (cache_dir_tmpl == NULL) {
goto done;
}
false, case_sensitive,
"template failed.\n"));
goto done;
}
} else {
goto done;
}
break;
case 'P':
if (!file_mode) {
goto done;
}
"because PID is not available.\n"));
goto done;
}
break;
/* Additional syntax from krb5.conf default_ccache_name */
case '{':
action = 'U';
n += L_EXP_UID - 1;
rerun = true;
continue;
action = 'U';
n += L_EXP_USERID - 1;
rerun = true;
continue;
/* SSSD does not distinguish betwen uid and euid,
* so we treat both the same way */
action = 'U';
n += L_EXP_EUID - 1;
rerun = true;
continue;
action = 'u';
n += L_EXP_USERNAME - 1;
rerun = true;
continue;
} else {
/* ignore any expansion variable we do not understand and
* let libkrb5 hndle it or fail */
name = n;
if (!n) {
"Invalid substitution sequence in cache "
"template. Missing closing '}' in [%s].\n",
template));
goto done;
}
}
break;
default:
goto done;
}
}
goto done;
}
p = n + 1;
}
goto done;
}
done:
return res;
}
{
if (private_path) {
"directory belonging to root or to [%d][%d].\n",
return EINVAL;
}
"the owner.\n"));
return EINVAL;
}
} else {
"others.\n"));
return EINVAL;
}
}
} else {
"directory.\n"));
return EINVAL;
}
"others.\n"));
return EINVAL;
}
}
return EOK;
}
struct string_list {
struct string_list *next;
struct string_list *prev;
char *s;
};
const char *ccdirname,
struct stat *parent_stat,
struct string_list **missing_parents)
{
char *end;
struct string_list *li;
("[%s] is not a directory.\n", ccdirname));
return EINVAL;
}
return EOK;
} else {
return ret;
}
}
("talloc_zero failed.\n"));
return ENOMEM;
}
("talloc_strdup failed.\n"));
return ENOMEM;
}
("talloc_strdup failed.\n"));
return ENOMEM;
}
/* We'll remove all trailing slashes from the back so that
do {
("Cannot find parent directory of [%s], / is not allowed.\n",
ccdirname));
goto done;
}
*end = '\0';
done:
return ret;
}
static errno_t
{
0, 0, NULL, 0);
if (ret == 0) {
("Illegal pattern in ccache directory name [%s].\n", filename));
return EINVAL;
} else if (ret == PCRE_ERROR_NOMATCH) {
("Ccache directory name [%s] does not contain "
"illegal patterns.\n", filename));
return EOK;
}
return EFAULT;
}
{
struct stat parent_stat;
("talloc_new failed.\n"));
return ENOMEM;
}
if (*ccdirname != '/') {
("Only absolute paths are allowed, not [%s] .\n", ccdirname));
goto done;
}
if (illegal_re != NULL) {
goto done;
}
}
("find_ccdir_parent_data failed.\n"));
goto done;
}
("check_parent_stat failed for %s directory [%s].\n",
goto done;
}
("Creating directory [%s].\n", li->s));
} else {
if (private_path &&
new_dir_mode = 0700;
} else {
new_dir_mode = 0755;
}
}
goto done;
}
if (private_path &&
goto done;
}
}
}
done:
return ret;
}
{
char *server_name;
const char *realm_name;
int realm_length;
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
if (server_name == NULL) {
goto done;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
if (kerr != 0) {
goto done;
}
kerr = 0;
done:
}
if (client_princ != NULL) {
}
if (server_princ != NULL) {
}
}
if (kerr != 0) {
return EIO;
}
return EOK;
}
static errno_t
{
char *ccdirname;
char *end;
goto done;
}
/* We'll remove all trailing slashes from the back so that
do {
"/ is not allowed.\n", ccdirname));
goto done;
}
*end = '\0';
done:
return ret;
}
static errno_t
check_cc_validity(const char *location,
const char *realm,
const char *princ,
bool *_valid)
{
bool valid = false;
if (krberr) {
return EIO;
}
/* KRB5_FCC_NOFILE would be returned if the directory components
* of the DIR cache do not exist, which is the case in /run
* after a reboot
*/
("ccache %s is missing or empty\n", location));
valid = false;
goto done;
} else if (krberr != 0) {
goto done;
}
("Could not check if ccache contains a valid principal\n"));
goto done;
}
done:
}
return ret;
}
struct sss_krb5_ccache {
};
static int sss_free_krb5_ccache(void *mem)
{
}
return 0;
}
const char *ccname,
struct sss_krb5_ccache **ccache)
{
struct sss_krb5_ccache *cc;
if (!cc) {
return ENOMEM;
}
if (ret) {
goto done;
}
if (kerr) {
goto done;
}
ret = ERR_NOT_FOUND;
goto done;
} else if (kerr != 0) {
ret = ERR_INTERNAL;
goto done;
}
done:
if (ret) {
} else {
}
return ret;
}
{
if (kerr) {
}
/* krb5_cc_destroy frees cc->ccache in all events */
return ret;
}
{
return ENOMEM;
}
if (ret) {
goto done;
}
done:
return ret;
}
/*======== ccache back end utilities ========*/
struct sss_krb5_cc_be *
{
switch (type) {
case SSS_KRB5_TYPE_FILE:
break;
#ifdef HAVE_KRB5_CC_COLLECTION
case SSS_KRB5_TYPE_DIR:
break;
case SSS_KRB5_TYPE_KEYRING:
be = &keyring_cc;
break;
#endif /* HAVE_KRB5_CC_COLLECTION */
case SSS_KRB5_TYPE_UNKNOWN:
break;
}
return be;
}
struct sss_krb5_cc_be *
get_cc_be_ops_ccache(const char *ccache)
{
enum sss_krb5_cc_type type;
return get_cc_be_ops(type);
}
/*======== Operations on the FILE: back end ========*/
{
const char *filename;
return EINVAL;
}
}
static errno_t
{
int ret;
bool active;
*result = false;
return EINVAL;
}
if (ret == -1) {
"it will be recreated\n", ccname));
*result = false;
return ENOENT;
}
return ret;
}
("Cache file [%s] exists, but is owned by [%d] instead of "
return EINVAL;
}
switch (type) {
#ifdef HAVE_KRB5_CC_COLLECTION
case SSS_KRB5_TYPE_DIR:
break;
#endif /* HAVE_KRB5_CC_COLLECTION */
case SSS_KRB5_TYPE_FILE:
break;
default:
return EINVAL;
}
if (ret == 0) {
("Cache file [%s] exists, but is not the expected type\n",
ccname));
return EINVAL;
}
return ret;
}
if (!active) {
} else {
("User [%d] is still active, reusing ccache [%s].\n",
*result = true;
}
return EOK;
}
static void
cc_check_template(const char *cc_template)
{
if (template_len >= 6 &&
"contain randomizing characters (XXXXXX), file might not "
"be rewritable\n", cc_template));
}
}
{
bool active;
bool valid;
const char *filename;
if (!filename) {
return EINVAL;
}
if (filename[0] != '/') {
return EINVAL;
}
("Could not check if ccache is active.\n"));
}
active = false;
return ret;
}
return ret;
}
return EOK;
}
const char *
const char *princ)
{
}
cc_file_remove(const char *location)
{
const char *filename;
if (!filename) {
return EINVAL;
}
if (filename[0] != '/') {
("Ccache file name [%s] is not an absolute path.\n", filename));
return EINVAL;
}
errno = 0;
return ret;
}
return EOK;
}
struct sss_krb5_cc_be file_cc = {
.create = cc_file_create,
.remove = cc_file_remove,
};
#ifdef HAVE_KRB5_CC_COLLECTION
/*======== Operations on the DIR: back end ========*/
{
const char *dir_name;
return EINVAL;
}
}
{
bool active;
bool active_primary = false;
bool valid;
enum sss_krb5_cc_type type;
const char *filename;
const char *dir;
char *tmp;
char *primary_file;
if (type != SSS_KRB5_TYPE_DIR) {
return EINVAL;
}
if (!filename) {
("Existing ccname does not contain path into the collection"));
return EINVAL;
}
if (filename[0] != '/') {
("Only absolute path names are allowed.\n"));
return EINVAL;
}
return ENOMEM;
}
if (!tmp) {
goto done;
}
if (!dir) {
("Cannot get base directory of %s.\n", tmp));
goto done;
}
} else {
}
("Could not check if ccache is active.\n"));
}
goto done;
}
/* If primary file isn't in ccache dir, we will ignore it.
* But if primary file has wrong permissions, we will fail.
*/
if (!primary_file) {
goto done;
}
("Could not check if file 'primary' [%s] in dir ccache"
" is active.\n", primary_file));
goto done;
}
goto done;
}
done:
return ret;
}
const char *
const char *princ)
{
const char *ccname;
if (!ccname) {
location));
return NULL;
}
/* ccname already points to a subsidiary cache */
}
if (krberr) {
return NULL;
}
if (krberr != 0) {
goto done;
}
/* This function is called only as a way to validate that,
* we have the right cache
*/
goto done;
}
/* everytime return location for dir_cache */
done:
return name;
}
cc_dir_remove(const char *location)
{
const char *subsidiary;
return EINVAL;
}
if (!subsidiary) {
location));
return EINVAL;
}
return cc_file_remove(subsidiary);
}
struct sss_krb5_cc_be dir_cc = {
.create = cc_dir_create,
};
/*======== Operations on the KEYRING: back end ========*/
{
const char *residual;
return EINVAL;
}
/* No special steps are needed to create a kernel keyring.
* Everything is handled in libkrb5.
*/
return EOK;
}
const char *cc_template, bool *_active,
bool *_valid)
{
bool active;
bool valid;
const char *residual;
if (!residual) {
("%s is not of type KEYRING:\n", location));
return EINVAL;
}
/* The keyring cache is always active */
active = true;
/* Check if any user is actively using this cache */
return ret;
}
return EOK;
}
const char *
const char *princ)
{
const char *residual;
size_t i;
if (!residual) {
location));
return NULL;
}
/* residual already points to a subsidiary cache if it of the
* form "KEYRING:<type>:<UID>:krb5_cc_XXXXXXX"
* For simplicity, we'll count the colons, up to three.
*/
i = count = 0;
if (residual[i] == ':') {
count ++;
}
i++;
}
if (count >= 3) {
}
if (krberr) {
return NULL;
}
if (krberr != 0) {
goto done;
}
goto done;
}
/* Always return the master name here.
* We do the above only to ensure that the
* principal-specific name exists and can
* be found.
*/
done:
return name;
}
cc_keyring_remove(const char *location)
{
const char *residual;
if (!residual) {
("%s is not of type KEYRING:\n", location));
return EINVAL;
}
/* No special steps are needed to create a kernel keyring.
* Everything is handled in libkrb5.
*/
return EOK;
}
struct sss_krb5_cc_be keyring_cc = {
};
#endif /* HAVE_KRB5_CC_COLLECTION */
char *domain_name,
struct sss_domain_info **dom)
{
if (domain_name != NULL &&
return ENOMEM;
}
} else {
}
return EOK;
}