|
Packit Service |
9f2c4a |
/* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
#include "config.h"
|
|
Packit Service |
9f2c4a |
#include <stdio.h>
|
|
Packit Service |
9f2c4a |
#include <sys/socket.h>
|
|
Packit Service |
9f2c4a |
#include <sys/syscall.h>
|
|
Packit Service |
9f2c4a |
#include <sys/types.h>
|
|
Packit Service |
9f2c4a |
#include <errno.h>
|
|
Packit Service |
9f2c4a |
#include <string.h>
|
|
Packit Service |
9f2c4a |
#include <pwd.h>
|
|
Packit Service |
9f2c4a |
#include <unistd.h>
|
|
Packit Service |
9f2c4a |
#include <krb5/krb5.h>
|
|
Packit Service |
9f2c4a |
#include <gssapi/gssapi_krb5.h>
|
|
Packit Service |
9f2c4a |
#include "gp_proxy.h"
|
|
Packit Service |
9f2c4a |
#include "gp_rpc_creds.h"
|
|
Packit Service |
9f2c4a |
#include "gp_creds.h"
|
|
Packit Service |
9f2c4a |
#include "gp_conv.h"
|
|
Packit Service |
9f2c4a |
#include "gp_export.h"
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
#define GSS_MECH_KRB5_OID_LENGTH 9
|
|
Packit Service |
9f2c4a |
#define GSS_MECH_KRB5_OID "\052\206\110\206\367\022\001\002\002"
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
gss_OID_desc gp_mech_krb5 = { GSS_MECH_KRB5_OID_LENGTH,
|
|
Packit Service |
9f2c4a |
discard_const(GSS_MECH_KRB5_OID) };
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
struct supported_mechs_map {
|
|
Packit Service |
9f2c4a |
int internal_id;
|
|
Packit Service |
9f2c4a |
const gss_OID mech;
|
|
Packit Service |
9f2c4a |
} supported_mechs_map[] = {
|
|
Packit Service |
9f2c4a |
{ GP_CRED_KRB5, &gp_mech_krb5 },
|
|
Packit Service |
9f2c4a |
{ 0, NULL }
|
|
Packit Service |
9f2c4a |
};
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
bool gp_creds_allowed_mech(struct gp_call_ctx *gpcall, gss_OID desired_mech)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
int i;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
for (i = 0; supported_mechs_map[i].internal_id != 0; i++) {
|
|
Packit Service |
9f2c4a |
if (gpcall->service->mechs & supported_mechs_map[i].internal_id) {
|
|
Packit Service |
9f2c4a |
if (gss_oid_equal(desired_mech, supported_mechs_map[i].mech)) {
|
|
Packit Service |
9f2c4a |
return true;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
return false;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
uint32_t gp_get_supported_mechs(uint32_t *min, gss_OID_set *set)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min;
|
|
Packit Service |
9f2c4a |
int i;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_create_empty_oid_set(&ret_min, set);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
for (i = 0; supported_mechs_map[i].internal_id != 0; i++) {
|
|
Packit Service |
9f2c4a |
ret_maj = gss_add_oid_set_member(&ret_min,
|
|
Packit Service |
9f2c4a |
supported_mechs_map[i].mech, set);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
gss_release_oid_set(&ret_min, set);
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
*min = 0;
|
|
Packit Service |
9f2c4a |
return GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
struct gp_service *gp_creds_match_conn(struct gssproxy_ctx *gpctx,
|
|
Packit Service |
9f2c4a |
struct gp_conn *conn)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
struct gp_creds *gcs;
|
|
Packit Service |
9f2c4a |
const char *socket;
|
|
Packit Service |
9f2c4a |
const char *program;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
gcs = gp_conn_get_creds(conn);
|
|
Packit Service |
9f2c4a |
socket = gp_conn_get_socket(conn);
|
|
Packit Service |
9f2c4a |
program = gp_conn_get_program(conn);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
for (int i = 0; i < gpctx->config->num_svcs; i++) {
|
|
Packit Service |
9f2c4a |
struct gp_service *svc = gpctx->config->svcs[i];
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if ((!svc->any_uid && svc->euid != gcs->ucred.uid) ||
|
|
Packit Service |
9f2c4a |
!gp_conn_check_selinux(conn, svc->selinux_ctx) ||
|
|
Packit Service |
9f2c4a |
(svc->program && !gp_same(program, svc->program)) ||
|
|
Packit Service |
9f2c4a |
(svc->socket && !gp_same(socket, svc->socket)) ||
|
|
Packit Service |
9f2c4a |
(!svc->socket && !gp_same(socket, gpctx->config->socket_name))) {
|
|
Packit Service |
9f2c4a |
continue;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
GPDEBUGN(2, "Connection matched service %s\n", svc->name);
|
|
Packit Service |
9f2c4a |
return svc;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
GPDEBUGN(2, "No matching service found\n");
|
|
Packit Service |
9f2c4a |
return NULL;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
#define PWBUFLEN 2048
|
|
Packit Service |
9f2c4a |
static char *uid_to_name(uid_t uid)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
struct passwd pwd, *res = NULL;
|
|
Packit Service |
9f2c4a |
char buffer[PWBUFLEN];
|
|
Packit Service |
9f2c4a |
int ret;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret = getpwuid_r(uid, &pwd, buffer, PWBUFLEN, &res;;
|
|
Packit Service |
9f2c4a |
if (ret || !res) {
|
|
Packit Service |
9f2c4a |
return NULL;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
return strdup(pwd.pw_name);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static char *get_formatted_string(const char *orig, uid_t target_uid)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
int len, left, right;
|
|
Packit Service |
9f2c4a |
char *user = NULL;
|
|
Packit Service |
9f2c4a |
char *str;
|
|
Packit Service |
9f2c4a |
char *tmp;
|
|
Packit Service |
9f2c4a |
char *p;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
str = strdup(orig);
|
|
Packit Service |
9f2c4a |
if (!str) {
|
|
Packit Service |
9f2c4a |
return NULL;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
len = strlen(str);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
p = str;
|
|
Packit Service |
9f2c4a |
while ((p = strchr(p, '%')) != NULL) {
|
|
Packit Service |
9f2c4a |
p++;
|
|
Packit Service |
9f2c4a |
switch (*p) {
|
|
Packit Service |
9f2c4a |
case '%':
|
|
Packit Service |
9f2c4a |
left = p - str;
|
|
Packit Service |
9f2c4a |
memmove(p, p + 1, left - 1);
|
|
Packit Service |
9f2c4a |
len--;
|
|
Packit Service |
9f2c4a |
continue;
|
|
Packit Service |
9f2c4a |
case 'U':
|
|
Packit Service |
9f2c4a |
p++;
|
|
Packit Service |
9f2c4a |
left = p - str;
|
|
Packit Service |
9f2c4a |
right = len - left;
|
|
Packit Service |
9f2c4a |
len = asprintf(&tmp, "%.*s%d%s", left - 2, str, target_uid, p);
|
|
Packit Service |
9f2c4a |
safefree(str);
|
|
Packit Service |
9f2c4a |
if (len == -1) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
str = tmp;
|
|
Packit Service |
9f2c4a |
p = str + (len - right);
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
case 'u':
|
|
Packit Service |
9f2c4a |
if (!user) {
|
|
Packit Service |
9f2c4a |
user = uid_to_name(target_uid);
|
|
Packit Service |
9f2c4a |
if (!user) {
|
|
Packit Service |
9f2c4a |
safefree(str);
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
p++;
|
|
Packit Service |
9f2c4a |
left = p - str;
|
|
Packit Service |
9f2c4a |
right = len - left;
|
|
Packit Service |
9f2c4a |
len = asprintf(&tmp, "%.*s%s%s", left - 2, str, user, p);
|
|
Packit Service |
9f2c4a |
safefree(str);
|
|
Packit Service |
9f2c4a |
if (len == -1) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
str = tmp;
|
|
Packit Service |
9f2c4a |
p = str + (len - right);
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
default:
|
|
Packit Service |
9f2c4a |
GPDEBUG("Invalid format code '%%%c'\n", *p);
|
|
Packit Service |
9f2c4a |
safefree(str);
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
safefree(user);
|
|
Packit Service |
9f2c4a |
return str;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
int gp_get_acquire_type(struct gssx_arg_acquire_cred *arg)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
struct gssx_option *val = NULL;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
gp_options_find(val, arg->options,
|
|
Packit Service |
9f2c4a |
ACQUIRE_TYPE_OPTION, sizeof(ACQUIRE_TYPE_OPTION));
|
|
Packit Service |
9f2c4a |
if (val) {
|
|
Packit Service |
9f2c4a |
if (gp_option_value_match(val, ACQUIRE_IMPERSONATE_NAME,
|
|
Packit Service |
9f2c4a |
sizeof(ACQUIRE_IMPERSONATE_NAME))) {
|
|
Packit Service |
9f2c4a |
return ACQ_IMPNAME;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
return -1;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
return ACQ_NORMAL;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static bool try_impersonate(struct gp_service *svc,
|
|
Packit Service |
9f2c4a |
gss_cred_usage_t cred_usage,
|
|
Packit Service |
9f2c4a |
enum gp_aqcuire_cred_type acquire_type)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
if (acquire_type == ACQ_IMPNAME &&
|
|
Packit Service |
9f2c4a |
(svc->allow_proto_trans || svc->trusted)) {
|
|
Packit Service |
9f2c4a |
return true;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
if (svc->impersonate &&
|
|
Packit Service |
9f2c4a |
(cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)) {
|
|
Packit Service |
9f2c4a |
return true;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
return false;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static void safe_free_mem_ccache(void *data)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
krb5_error_code e;
|
|
Packit Service |
9f2c4a |
krb5_context ctx = NULL;
|
|
Packit Service |
9f2c4a |
krb5_ccache cc = NULL;
|
|
Packit Service |
9f2c4a |
char *ccname = (char *) data;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (!ccname) {
|
|
Packit Service |
9f2c4a |
return;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
e = krb5_init_context(&ctx;;
|
|
Packit Service |
9f2c4a |
if (e != 0) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
e = krb5_cc_resolve(ctx, ccname, &cc);
|
|
Packit Service |
9f2c4a |
if (e != 0) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* also closes handle */
|
|
Packit Service |
9f2c4a |
krb5_cc_destroy(ctx, cc);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
if (ctx) {
|
|
Packit Service |
9f2c4a |
krb5_free_context(ctx);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
free(ccname);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static int ensure_segregated_ccache(struct gp_call_ctx *gpcall,
|
|
Packit Service |
9f2c4a |
int cc_num,
|
|
Packit Service |
9f2c4a |
gss_key_value_set_desc *cs)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
int ret;
|
|
Packit Service |
9f2c4a |
char *buf;
|
|
Packit Service |
9f2c4a |
pid_t tid = -1;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (cc_num != -1) {
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* We always have space for at least 1 more entry in cs. */
|
|
Packit Service |
9f2c4a |
cc_num = cs->count;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->elements[cc_num].key = strdup("ccache");
|
|
Packit Service |
9f2c4a |
if (!cs->elements[cc_num].key) {
|
|
Packit Service |
9f2c4a |
return ENOMEM;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
do {
|
|
Packit Service |
9f2c4a |
errno = 0;
|
|
Packit Service |
9f2c4a |
tid = syscall(SYS_gettid);
|
|
Packit Service |
9f2c4a |
} while (tid == -1 && errno == EINTR);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret = asprintf(&buf, "MEMORY:internal_%d", tid);
|
|
Packit Service |
9f2c4a |
if (ret == -1) {
|
|
Packit Service |
9f2c4a |
return ENOMEM;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
gpcall->destroy_callback = safe_free_mem_ccache;
|
|
Packit Service |
9f2c4a |
gpcall->destroy_callback_data = buf;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->elements[cc_num].value = strdup(buf);
|
|
Packit Service |
9f2c4a |
if (!cs->elements[cc_num].value) {
|
|
Packit Service |
9f2c4a |
return ENOMEM;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->count = cc_num + 1;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static int gp_get_cred_environment(struct gp_call_ctx *gpcall,
|
|
Packit Service |
9f2c4a |
gssx_name *desired_name,
|
|
Packit Service |
9f2c4a |
gss_name_t *requested_name,
|
|
Packit Service |
9f2c4a |
gss_cred_usage_t *cred_usage,
|
|
Packit Service |
9f2c4a |
gss_key_value_set_desc *cs)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
struct gp_service *svc;
|
|
Packit Service |
9f2c4a |
gss_name_t name = GSS_C_NO_NAME;
|
|
Packit Service |
9f2c4a |
gss_buffer_desc namebuf;
|
|
Packit Service |
9f2c4a |
gss_OID_desc name_type;
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
uid_t target_uid;
|
|
Packit Service |
9f2c4a |
bool user_requested = false;
|
|
Packit Service |
9f2c4a |
bool use_service_keytab = false;
|
|
Packit Service |
9f2c4a |
int ret = -1;
|
|
Packit Service |
9f2c4a |
int k_num = -1;
|
|
Packit Service |
9f2c4a |
int ck_num = -1;
|
|
Packit Service |
9f2c4a |
int cc_num = -1;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
memset(cs, 0, sizeof(gss_key_value_set_desc));
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
target_uid = gp_conn_get_uid(gpcall->connection);
|
|
Packit Service |
9f2c4a |
svc = gpcall->service;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* filter based on cred_usage */
|
|
Packit Service |
9f2c4a |
if (svc->cred_usage != GSS_C_BOTH) {
|
|
Packit Service |
9f2c4a |
if (*cred_usage == GSS_C_BOTH) {
|
|
Packit Service |
9f2c4a |
*cred_usage = svc->cred_usage;
|
|
Packit Service |
9f2c4a |
} else if (svc->cred_usage != *cred_usage) {
|
|
Packit Service |
9f2c4a |
ret = EACCES;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (desired_name) {
|
|
Packit Service |
9f2c4a |
gp_conv_gssx_to_oid(&desired_name->name_type, &name_type);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* A service retains the trusted flag only if the current uid matches
|
|
Packit Service |
9f2c4a |
* the configured euid */
|
|
Packit Service |
9f2c4a |
if (svc->trusted &&
|
|
Packit Service |
9f2c4a |
(svc->euid == target_uid) &&
|
|
Packit Service |
9f2c4a |
(gss_oid_equal(&name_type, GSS_C_NT_STRING_UID_NAME) ||
|
|
Packit Service |
9f2c4a |
gss_oid_equal(&name_type, GSS_C_NT_MACHINE_UID_NAME))) {
|
|
Packit Service |
9f2c4a |
target_uid = atol(desired_name->display_name.octet_string_val);
|
|
Packit Service |
9f2c4a |
user_requested = true;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
/* it's a user request if it comes from an arbitrary uid */
|
|
Packit Service |
9f2c4a |
if (svc->euid != target_uid) {
|
|
Packit Service |
9f2c4a |
user_requested = true;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
use_service_keytab = true;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
ret_maj = gp_conv_gssx_to_name(&ret_min, desired_name, &name);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
*requested_name = name;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
/* No name provided */
|
|
Packit Service |
9f2c4a |
if (svc->trusted && (svc->euid == target_uid)) {
|
|
Packit Service |
9f2c4a |
use_service_keytab = true;
|
|
Packit Service |
9f2c4a |
} else if (svc->euid != target_uid) {
|
|
Packit Service |
9f2c4a |
user_requested = true;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* impersonation case (only for initiation) */
|
|
Packit Service |
9f2c4a |
if (user_requested) {
|
|
Packit Service |
9f2c4a |
if (try_impersonate(svc, *cred_usage, ACQ_NORMAL)) {
|
|
Packit Service |
9f2c4a |
char *str;
|
|
Packit Service |
9f2c4a |
/* When impersonating we want to use the service keytab to
|
|
Packit Service |
9f2c4a |
* acquire initial credential ... */
|
|
Packit Service |
9f2c4a |
use_service_keytab = true;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* ... and after that make the s4u2self delegation dance with the
|
|
Packit Service |
9f2c4a |
* target name identifying the user */
|
|
Packit Service |
9f2c4a |
str = uid_to_name(target_uid);
|
|
Packit Service |
9f2c4a |
if (str == NULL) {
|
|
Packit Service |
9f2c4a |
GPERROR("Failed to get username from uid %d\n", target_uid);
|
|
Packit Service |
9f2c4a |
return ENOENT;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
namebuf.value = str;
|
|
Packit Service |
9f2c4a |
namebuf.length = strlen(str);
|
|
Packit Service |
9f2c4a |
ret_maj = gss_import_name(&ret_min, &namebuf,
|
|
Packit Service |
9f2c4a |
GSS_C_NT_USER_NAME, requested_name);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
GPERROR("Failed to import username %s\n", str);
|
|
Packit Service |
9f2c4a |
safefree(str);
|
|
Packit Service |
9f2c4a |
return ENOMEM;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
safefree(str);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (use_service_keytab &&
|
|
Packit Service |
9f2c4a |
(*requested_name == GSS_C_NO_NAME) && (svc->krb5.principal)) {
|
|
Packit Service |
9f2c4a |
/* configuration dictates to use a specific name */
|
|
Packit Service |
9f2c4a |
gss_buffer_desc const_buf;
|
|
Packit Service |
9f2c4a |
const_buf.value = svc->krb5.principal;
|
|
Packit Service |
9f2c4a |
const_buf.length = strlen(svc->krb5.principal) + 1;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_import_name(&ret_min, &const_buf,
|
|
Packit Service |
9f2c4a |
discard_const(GSS_KRB5_NT_PRINCIPAL_NAME),
|
|
Packit Service |
9f2c4a |
requested_name);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
GPERROR("Failed to import krb5_principal name %s\n",
|
|
Packit Service |
9f2c4a |
svc->krb5.principal);
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (svc->krb5.store.count == 0) {
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* allocate 2 more than in source, just in case we need to add
|
|
Packit Service |
9f2c4a |
* an internal client_keytab element and ccache */
|
|
Packit Service |
9f2c4a |
cs->elements = calloc(svc->krb5.store.count + 2,
|
|
Packit Service |
9f2c4a |
sizeof(gss_key_value_element_desc));
|
|
Packit Service |
9f2c4a |
if (!cs->elements) {
|
|
Packit Service |
9f2c4a |
ret = ENOMEM;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
for (unsigned d = 0; d < svc->krb5.store.count; d++) {
|
|
Packit Service |
9f2c4a |
if (strcmp(svc->krb5.store.elements[d].key, "client_keytab") == 0) {
|
|
Packit Service |
9f2c4a |
ck_num = cs->count;
|
|
Packit Service |
9f2c4a |
} else if (strcmp(svc->krb5.store.elements[d].key, "keytab") == 0) {
|
|
Packit Service |
9f2c4a |
k_num = cs->count;
|
|
Packit Service |
9f2c4a |
} else if (strcmp(svc->krb5.store.elements[d].key, "ccache") == 0) {
|
|
Packit Service |
9f2c4a |
cc_num = cs->count;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->elements[cs->count].key = strdup(svc->krb5.store.elements[d].key);
|
|
Packit Service |
9f2c4a |
if (!cs->elements[cs->count].key) {
|
|
Packit Service |
9f2c4a |
ret = ENOMEM;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->elements[cs->count].value =
|
|
Packit Service |
9f2c4a |
get_formatted_string(svc->krb5.store.elements[d].value,
|
|
Packit Service |
9f2c4a |
target_uid);
|
|
Packit Service |
9f2c4a |
if (!cs->elements[cs->count].value) {
|
|
Packit Service |
9f2c4a |
safefree(cs->elements[cs->count].key);
|
|
Packit Service |
9f2c4a |
GPDEBUG("Failed to build credential store formatted string.\n");
|
|
Packit Service |
9f2c4a |
ret = ENOMEM;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->count++;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* when a user is not explicitly requested then it means the calling
|
|
Packit Service |
9f2c4a |
* application wants to use the credentials in the standard keytab,
|
|
Packit Service |
9f2c4a |
* if any. */
|
|
Packit Service |
9f2c4a |
if (use_service_keytab) {
|
|
Packit Service |
9f2c4a |
if (k_num == -1) {
|
|
Packit Service |
9f2c4a |
if (ck_num == -1) {
|
|
Packit Service |
9f2c4a |
ret = EINVAL;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
/* allow a service to define only the client keytab */
|
|
Packit Service |
9f2c4a |
ret = 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
if (ck_num == -1) {
|
|
Packit Service |
9f2c4a |
/* we always have space for 1 more */
|
|
Packit Service |
9f2c4a |
ck_num = cs->count;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->elements[ck_num].key = strdup("client_keytab");
|
|
Packit Service |
9f2c4a |
if (!cs->elements[ck_num].key) {
|
|
Packit Service |
9f2c4a |
ret = ENOMEM;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
cs->count = ck_num + 1;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
safefree(cs->elements[ck_num].value);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
cs->elements[ck_num].value = strdup(cs->elements[k_num].value);
|
|
Packit Service |
9f2c4a |
if (!cs->elements[ck_num].value) {
|
|
Packit Service |
9f2c4a |
ret = ENOMEM;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret = ensure_segregated_ccache(gpcall, cc_num, cs);
|
|
Packit Service |
9f2c4a |
if (ret != 0) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret = 0;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
if (ret) {
|
|
Packit Service |
9f2c4a |
free_cred_store_elements(cs);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
return ret;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static uint32_t gp_check_cred(uint32_t *min,
|
|
Packit Service |
9f2c4a |
gss_cred_id_t in_cred,
|
|
Packit Service |
9f2c4a |
gssx_name *desired_name,
|
|
Packit Service |
9f2c4a |
gss_cred_usage_t cred_usage)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
uint32_t discard;
|
|
Packit Service |
9f2c4a |
uint32_t i;
|
|
Packit Service |
9f2c4a |
gss_name_t req_name = GSS_C_NO_NAME;
|
|
Packit Service |
9f2c4a |
gss_name_t check_name = GSS_C_NO_NAME;
|
|
Packit Service |
9f2c4a |
gss_OID_set mechanisms = GSS_C_NO_OID_SET;
|
|
Packit Service |
9f2c4a |
gss_cred_usage_t usage;
|
|
Packit Service |
9f2c4a |
uint32_t lifetime;
|
|
Packit Service |
9f2c4a |
int present = 0;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_inquire_cred(&ret_min, in_cred,
|
|
Packit Service |
9f2c4a |
desired_name?&check_name:NULL,
|
|
Packit Service |
9f2c4a |
&lifetime, &usage, &mechanisms);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
for (i = 0; i < mechanisms->count; i++) {
|
|
Packit Service |
9f2c4a |
present = gss_oid_equal(&mechanisms->elements[i], gss_mech_krb5);
|
|
Packit Service |
9f2c4a |
if (present) break;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
if (!present) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_CRED_UNAVAIL;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (desired_name) {
|
|
Packit Service |
9f2c4a |
int equal;
|
|
Packit Service |
9f2c4a |
ret_maj = gp_conv_gssx_to_name(&ret_min, desired_name, &req_name);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
ret_maj = gss_compare_name(&ret_min, req_name, check_name, &equal);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
if (!equal) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_CRED_UNAVAIL;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
switch (cred_usage) {
|
|
Packit Service |
9f2c4a |
case GSS_C_ACCEPT:
|
|
Packit Service |
9f2c4a |
if (usage == GSS_C_INITIATE) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_NO_CRED;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
case GSS_C_INITIATE:
|
|
Packit Service |
9f2c4a |
if (usage == GSS_C_ACCEPT) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_NO_CRED;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
case GSS_C_BOTH:
|
|
Packit Service |
9f2c4a |
if (usage != GSS_C_BOTH) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_NO_CRED;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (lifetime == 0) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_CREDENTIALS_EXPIRED;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
gss_release_oid_set(&discard, &mechanisms);
|
|
Packit Service |
9f2c4a |
gss_release_name(&discard, &check_name);
|
|
Packit Service |
9f2c4a |
gss_release_name(&discard, &req_name);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
uint32_t gp_add_krb5_creds(uint32_t *min,
|
|
Packit Service |
9f2c4a |
struct gp_call_ctx *gpcall,
|
|
Packit Service |
9f2c4a |
enum gp_aqcuire_cred_type acquire_type,
|
|
Packit Service |
9f2c4a |
gss_cred_id_t in_cred,
|
|
Packit Service |
9f2c4a |
gssx_name *desired_name,
|
|
Packit Service |
9f2c4a |
gss_cred_usage_t cred_usage,
|
|
Packit Service |
9f2c4a |
uint32_t initiator_time_req UNUSED,
|
|
Packit Service |
9f2c4a |
uint32_t acceptor_time_req UNUSED,
|
|
Packit Service |
9f2c4a |
gss_cred_id_t *output_cred_handle,
|
|
Packit Service |
9f2c4a |
gss_OID_set *actual_mechs,
|
|
Packit Service |
9f2c4a |
uint32_t *initiator_time_rec,
|
|
Packit Service |
9f2c4a |
uint32_t *acceptor_time_rec)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
uint32_t discard;
|
|
Packit Service |
9f2c4a |
gss_name_t req_name = GSS_C_NO_NAME;
|
|
Packit Service |
9f2c4a |
gss_OID_set_desc desired_mechs = { 1, &gp_mech_krb5 };
|
|
Packit Service |
9f2c4a |
gss_key_value_set_desc cred_store = { 0 };
|
|
Packit Service |
9f2c4a |
gss_cred_id_t impersonator_cred = GSS_C_NO_CREDENTIAL;
|
|
Packit Service |
9f2c4a |
gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL;
|
|
Packit Service |
9f2c4a |
gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
|
|
Packit Service |
9f2c4a |
gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;
|
|
Packit Service |
9f2c4a |
gss_name_t target_name = GSS_C_NO_NAME;
|
|
Packit Service |
9f2c4a |
gss_buffer_desc init_token = GSS_C_EMPTY_BUFFER;
|
|
Packit Service |
9f2c4a |
gss_buffer_desc accept_token = GSS_C_EMPTY_BUFFER;
|
|
Packit Service |
9f2c4a |
gss_cred_id_t input_cred;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (!min || !output_cred_handle) {
|
|
Packit Service |
9f2c4a |
return GSS_S_CALL_INACCESSIBLE_WRITE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
*min = 0;
|
|
Packit Service |
9f2c4a |
*output_cred_handle = GSS_C_NO_CREDENTIAL;
|
|
Packit Service |
9f2c4a |
if (actual_mechs) {
|
|
Packit Service |
9f2c4a |
*actual_mechs = GSS_C_NO_OID_SET;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (in_cred != GSS_C_NO_CREDENTIAL && acquire_type != ACQ_IMPNAME) {
|
|
Packit Service |
9f2c4a |
/* NOTE: we can't yet handle adding to an existing credential due
|
|
Packit Service |
9f2c4a |
* to the way gss_krb5_import_cred works. This limitation should
|
|
Packit Service |
9f2c4a |
* be removed by adding a gssapi extension that superceedes this
|
|
Packit Service |
9f2c4a |
* function completely */
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* just check if it is a valid krb5 cred */
|
|
Packit Service |
9f2c4a |
ret_maj = gp_check_cred(&ret_min, in_cred, desired_name, cred_usage);
|
|
Packit Service |
9f2c4a |
if (ret_maj == GSS_S_COMPLETE) {
|
|
Packit Service |
9f2c4a |
return GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
} else if (ret_maj == GSS_S_CREDENTIALS_EXPIRED ||
|
|
Packit Service |
9f2c4a |
ret_maj == GSS_S_NO_CRED) {
|
|
Packit Service |
9f2c4a |
/* continue and try to obtain new creds */
|
|
Packit Service |
9f2c4a |
ret_maj = 0;
|
|
Packit Service |
9f2c4a |
ret_min = 0;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return GSS_S_CRED_UNAVAIL;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (acquire_type == ACQ_NORMAL) {
|
|
Packit Service |
9f2c4a |
ret_min = gp_get_cred_environment(gpcall, desired_name, &req_name,
|
|
Packit Service |
9f2c4a |
&cred_usage, &cred_store);
|
|
Packit Service |
9f2c4a |
if (ret_min) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_CRED_UNAVAIL;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
} else if (desired_name) {
|
|
Packit Service |
9f2c4a |
ret_maj = gp_conv_gssx_to_name(&ret_min, desired_name, &req_name);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (!try_impersonate(gpcall->service, cred_usage, acquire_type)) {
|
|
Packit Service |
9f2c4a |
ret_maj = gss_acquire_cred_from(&ret_min, req_name, GSS_C_INDEFINITE,
|
|
Packit Service |
9f2c4a |
&desired_mechs, cred_usage,
|
|
Packit Service |
9f2c4a |
&cred_store, output_cred_handle,
|
|
Packit Service |
9f2c4a |
actual_mechs, NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
} else { /* impersonation */
|
|
Packit Service |
9f2c4a |
switch (acquire_type) {
|
|
Packit Service |
9f2c4a |
case ACQ_NORMAL:
|
|
Packit Service |
9f2c4a |
ret_maj = gss_acquire_cred_from(&ret_min, GSS_C_NO_NAME,
|
|
Packit Service |
9f2c4a |
GSS_C_INDEFINITE,
|
|
Packit Service |
9f2c4a |
&desired_mechs, GSS_C_BOTH,
|
|
Packit Service |
9f2c4a |
&cred_store, &impersonator_cred,
|
|
Packit Service |
9f2c4a |
NULL, NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
input_cred = impersonator_cred;
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
case ACQ_IMPNAME:
|
|
Packit Service |
9f2c4a |
input_cred = in_cred;
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
default:
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
ret_min = EFAULT;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_inquire_cred(&ret_min, input_cred,
|
|
Packit Service |
9f2c4a |
&target_name, NULL, NULL, NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_acquire_cred_impersonate_name(&ret_min,
|
|
Packit Service |
9f2c4a |
input_cred,
|
|
Packit Service |
9f2c4a |
req_name,
|
|
Packit Service |
9f2c4a |
GSS_C_INDEFINITE,
|
|
Packit Service |
9f2c4a |
&desired_mechs,
|
|
Packit Service |
9f2c4a |
GSS_C_INITIATE,
|
|
Packit Service |
9f2c4a |
&user_cred,
|
|
Packit Service |
9f2c4a |
actual_mechs, NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (acquire_type == ACQ_IMPNAME) {
|
|
Packit Service |
9f2c4a |
/* we are done here */
|
|
Packit Service |
9f2c4a |
*output_cred_handle = user_cred;
|
|
Packit Service |
9f2c4a |
user_cred = GSS_C_NO_CREDENTIAL;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* now acquire credentials for impersonated user to self */
|
|
Packit Service |
9f2c4a |
ret_maj = gss_init_sec_context(&ret_min, user_cred, &initiator_context,
|
|
Packit Service |
9f2c4a |
target_name, &gp_mech_krb5,
|
|
Packit Service |
9f2c4a |
GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
|
|
Packit Service |
9f2c4a |
GSS_C_INDEFINITE,
|
|
Packit Service |
9f2c4a |
GSS_C_NO_CHANNEL_BINDINGS,
|
|
Packit Service |
9f2c4a |
GSS_C_NO_BUFFER, NULL,
|
|
Packit Service |
9f2c4a |
&init_token, NULL, NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
/* accept context to be able to store delegated credentials */
|
|
Packit Service |
9f2c4a |
ret_maj = gss_accept_sec_context(&ret_min, &acceptor_context,
|
|
Packit Service |
9f2c4a |
input_cred, &init_token,
|
|
Packit Service |
9f2c4a |
GSS_C_NO_CHANNEL_BINDINGS,
|
|
Packit Service |
9f2c4a |
NULL, NULL, &accept_token,
|
|
Packit Service |
9f2c4a |
NULL, NULL, output_cred_handle);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (initiator_time_rec || acceptor_time_rec) {
|
|
Packit Service |
9f2c4a |
ret_maj = gss_inquire_cred_by_mech(&ret_min,
|
|
Packit Service |
9f2c4a |
*output_cred_handle,
|
|
Packit Service |
9f2c4a |
&gp_mech_krb5,
|
|
Packit Service |
9f2c4a |
NULL,
|
|
Packit Service |
9f2c4a |
initiator_time_rec,
|
|
Packit Service |
9f2c4a |
acceptor_time_rec,
|
|
Packit Service |
9f2c4a |
NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
gp_log_status(&gp_mech_krb5, ret_maj, ret_min);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (*output_cred_handle) {
|
|
Packit Service |
9f2c4a |
gss_release_cred(&discard, output_cred_handle);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
if (actual_mechs && *actual_mechs) {
|
|
Packit Service |
9f2c4a |
gss_release_oid_set(&discard, actual_mechs);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
free_cred_store_elements(&cred_store);
|
|
Packit Service |
9f2c4a |
gss_release_cred(&discard, &impersonator_cred);
|
|
Packit Service |
9f2c4a |
gss_release_cred(&discard, &user_cred);
|
|
Packit Service |
9f2c4a |
gss_release_name(&discard, &target_name);
|
|
Packit Service |
9f2c4a |
gss_delete_sec_context(&discard, &initiator_context, NULL);
|
|
Packit Service |
9f2c4a |
gss_release_buffer(&discard, &init_token);
|
|
Packit Service |
9f2c4a |
gss_release_buffer(&discard, &accept_token);
|
|
Packit Service |
9f2c4a |
gss_release_name(&discard, &req_name);
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
void gp_filter_flags(struct gp_call_ctx *gpcall, uint32_t *flags)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
*flags |= gpcall->service->enforce_flags;
|
|
Packit Service |
9f2c4a |
*flags &= ~gpcall->service->filter_flags;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static uint32_t get_impersonator_fallback(uint32_t *min, gss_cred_id_t cred,
|
|
Packit Service |
9f2c4a |
char **impersonator)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
char *memcache = NULL;
|
|
Packit Service |
9f2c4a |
krb5_context context = NULL;
|
|
Packit Service |
9f2c4a |
krb5_ccache ccache = NULL;
|
|
Packit Service |
9f2c4a |
krb5_data config;
|
|
Packit Service |
9f2c4a |
int err;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = krb5_init_context(&context);
|
|
Packit Service |
9f2c4a |
if (err) {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* Create a memory ccache we can iterate with libkrb5 functions */
|
|
Packit Service |
9f2c4a |
gss_key_value_element_desc ccelement = { "ccache", NULL };
|
|
Packit Service |
9f2c4a |
gss_key_value_set_desc cred_store = { 1, &ccelement };
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = asprintf(&memcache, "MEMORY:cred_allowed_%p", &memcache);
|
|
Packit Service |
9f2c4a |
if (err == -1) {
|
|
Packit Service |
9f2c4a |
memcache = NULL;
|
|
Packit Service |
9f2c4a |
ret_min = ENOMEM;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
cred_store.elements[0].value = memcache;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_store_cred_into(&ret_min, cred, GSS_C_INITIATE,
|
|
Packit Service |
9f2c4a |
discard_const(gss_mech_krb5), 1, 0,
|
|
Packit Service |
9f2c4a |
&cred_store, NULL, NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj != GSS_S_COMPLETE) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = krb5_cc_resolve(context, memcache, &ccache);
|
|
Packit Service |
9f2c4a |
if (err) {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = krb5_cc_get_config(context, ccache, NULL, "proxy_impersonator",
|
|
Packit Service |
9f2c4a |
&config);
|
|
Packit Service |
9f2c4a |
if (err == 0) {
|
|
Packit Service |
9f2c4a |
*impersonator = strndup(config.data, config.length);
|
|
Packit Service |
9f2c4a |
if (!*impersonator) {
|
|
Packit Service |
9f2c4a |
ret_min = ENOMEM;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
ret_min = 0;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
krb5_free_data_contents(context, &config);
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
if (context) {
|
|
Packit Service |
9f2c4a |
if (ccache) {
|
|
Packit Service |
9f2c4a |
krb5_cc_destroy(context, ccache);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
krb5_free_context(context);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
free(memcache);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
#if !HAVE_DECL_GSS_KRB5_GET_CRED_IMPERSONATOR
|
|
Packit Service |
9f2c4a |
gss_OID_desc impersonator_oid = {
|
|
Packit Service |
9f2c4a |
11, discard_const("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0e")
|
|
Packit Service |
9f2c4a |
};
|
|
Packit Service |
9f2c4a |
const gss_OID GSS_KRB5_GET_CRED_IMPERSONATOR = &impersonator_oid;
|
|
Packit Service |
9f2c4a |
#endif
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static uint32_t get_impersonator_name(uint32_t *min, gss_cred_id_t cred,
|
|
Packit Service |
9f2c4a |
char **impersonator)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
uint32_t discard;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
*impersonator = NULL;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_inquire_cred_by_oid(&ret_min, cred,
|
|
Packit Service |
9f2c4a |
GSS_KRB5_GET_CRED_IMPERSONATOR,
|
|
Packit Service |
9f2c4a |
&bufset);
|
|
Packit Service |
9f2c4a |
if (ret_maj == GSS_S_COMPLETE) {
|
|
Packit Service |
9f2c4a |
if (bufset->count == 0) {
|
|
Packit Service |
9f2c4a |
ret_min = ENOENT;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
*impersonator = strndup(bufset->elements[0].value,
|
|
Packit Service |
9f2c4a |
bufset->elements[0].length);
|
|
Packit Service |
9f2c4a |
if (!*impersonator) {
|
|
Packit Service |
9f2c4a |
ret_min = ENOMEM;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
} else if (ret_maj == GSS_S_UNAVAILABLE) {
|
|
Packit Service |
9f2c4a |
/* Not supported by krb5 library yet, fallback to raw krb5 calls */
|
|
Packit Service |
9f2c4a |
/* TODO: Remove once we set a minimum required dependency on a
|
|
Packit Service |
9f2c4a |
* release that supports this call */
|
|
Packit Service |
9f2c4a |
ret_maj = get_impersonator_fallback(&ret_min, cred, impersonator);
|
|
Packit Service |
9f2c4a |
if (ret_maj == GSS_S_FAILURE) {
|
|
Packit Service |
9f2c4a |
if (ret_min == (uint32_t)KRB5_CC_NOTFOUND) {
|
|
Packit Service |
9f2c4a |
ret_min = ENOENT;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
(void)gss_release_buffer_set(&discard, &bufset);
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
static uint32_t check_impersonator_name(uint32_t *min,
|
|
Packit Service |
9f2c4a |
gss_name_t target_name,
|
|
Packit Service |
9f2c4a |
const char *impersonator)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
gss_name_t canon_name = NULL;
|
|
Packit Service |
9f2c4a |
gss_buffer_desc buf;
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
uint32_t discard;
|
|
Packit Service |
9f2c4a |
bool match;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_canonicalize_name(&discard, target_name, &gp_mech_krb5,
|
|
Packit Service |
9f2c4a |
&canon_name);
|
|
Packit Service |
9f2c4a |
if (ret_maj != GSS_S_COMPLETE) {
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_display_name(&discard, canon_name, &buf, NULL);
|
|
Packit Service |
9f2c4a |
gss_release_name(&discard, &canon_name);
|
|
Packit Service |
9f2c4a |
if (ret_maj != GSS_S_COMPLETE) {
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
match = (strncmp(impersonator, buf.value, buf.length) == 0) &&
|
|
Packit Service |
9f2c4a |
(strlen(impersonator) == buf.length);
|
|
Packit Service |
9f2c4a |
gss_release_buffer(&discard, &buf;;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
*min = 0;
|
|
Packit Service |
9f2c4a |
if (match) {
|
|
Packit Service |
9f2c4a |
return GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
return GSS_S_UNAUTHORIZED;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
uint32_t gp_cred_allowed(uint32_t *min,
|
|
Packit Service |
9f2c4a |
struct gp_call_ctx *gpcall,
|
|
Packit Service |
9f2c4a |
gss_cred_id_t cred,
|
|
Packit Service |
9f2c4a |
gss_name_t target_name)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
char *impersonator = NULL;
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (cred == GSS_C_NO_CREDENTIAL) {
|
|
Packit Service |
9f2c4a |
return GSS_S_CRED_UNAVAIL;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (gpcall->service->trusted ||
|
|
Packit Service |
9f2c4a |
gpcall->service->impersonate ||
|
|
Packit Service |
9f2c4a |
gpcall->service->allow_const_deleg) {
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
GPDEBUGN(2, "Credentials allowed by configuration\n");
|
|
Packit Service |
9f2c4a |
*min = 0;
|
|
Packit Service |
9f2c4a |
return GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = get_impersonator_name(&ret_min, cred, &impersonator);
|
|
Packit Service |
9f2c4a |
if (ret_maj) goto done;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* if we find an impersonator entry we bail as that is not authorized,
|
|
Packit Service |
9f2c4a |
* *unless* the target is the impersonator itself! If the operation
|
|
Packit Service |
9f2c4a |
* were authorized then gpcall->service->allow_const_deleg would have
|
|
Packit Service |
9f2c4a |
* caused the ealier check to return GSS_S_COMPLETE already */
|
|
Packit Service |
9f2c4a |
if (impersonator != NULL) {
|
|
Packit Service |
9f2c4a |
ret_maj = check_impersonator_name(&ret_min, target_name, impersonator);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
switch (ret_maj) {
|
|
Packit Service |
9f2c4a |
case GSS_S_UNAUTHORIZED:
|
|
Packit Service |
9f2c4a |
GPDEBUGN(2, "Unauthorized impersonator credentials detected\n");
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
case GSS_S_COMPLETE:
|
|
Packit Service |
9f2c4a |
if (impersonator) {
|
|
Packit Service |
9f2c4a |
GPDEBUGN(2, "Credentials allowed for 'self'\n");
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
GPDEBUGN(2, "No impersonator credentials detected\n");
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
default:
|
|
Packit Service |
9f2c4a |
GPDEBUG("Failure while checking credentials\n");
|
|
Packit Service |
9f2c4a |
break;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
free(impersonator);
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
uint32_t gp_count_tickets(uint32_t *min, gss_cred_id_t cred, uint32_t *ccsum)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
char *memcache = NULL;
|
|
Packit Service |
9f2c4a |
krb5_context context = NULL;
|
|
Packit Service |
9f2c4a |
krb5_ccache ccache = NULL;
|
|
Packit Service |
9f2c4a |
krb5_cc_cursor cursor = NULL;
|
|
Packit Service |
9f2c4a |
krb5_creds creds;
|
|
Packit Service |
9f2c4a |
int err;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = krb5_init_context(&context);
|
|
Packit Service |
9f2c4a |
if (err != 0) {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* Create a memory ccache we can iterate with libkrb5 functions */
|
|
Packit Service |
9f2c4a |
gss_key_value_element_desc ccelement = { "ccache", NULL };
|
|
Packit Service |
9f2c4a |
gss_key_value_set_desc cred_store = { 1, &ccelement };
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = asprintf(&memcache, "MEMORY:cred_allowed_%p", &memcache);
|
|
Packit Service |
9f2c4a |
if (err == -1) {
|
|
Packit Service |
9f2c4a |
memcache = NULL;
|
|
Packit Service |
9f2c4a |
ret_min = ENOMEM;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
cred_store.elements[0].value = memcache;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gss_store_cred_into(&ret_min, cred, GSS_C_INITIATE,
|
|
Packit Service |
9f2c4a |
discard_const(gss_mech_krb5), 1, 0,
|
|
Packit Service |
9f2c4a |
&cred_store, NULL, NULL);
|
|
Packit Service |
9f2c4a |
if (ret_maj != GSS_S_COMPLETE) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = krb5_cc_resolve(context, memcache, &ccache);
|
|
Packit Service |
9f2c4a |
if (err != 0) {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = krb5_cc_start_seq_get(context, ccache, &cursor);
|
|
Packit Service |
9f2c4a |
if (err != 0) {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
do {
|
|
Packit Service |
9f2c4a |
err = krb5_cc_next_cred(context, ccache, &cursor, &creds);
|
|
Packit Service |
9f2c4a |
if (err != 0 && err != KRB5_CC_END) {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
krb5_free_cred_contents(context, &creds);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* TODO: Should we do a real checksum over all creds->ticket data and
|
|
Packit Service |
9f2c4a |
* flags in future ? */
|
|
Packit Service |
9f2c4a |
(*ccsum)++;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
} while (err == 0);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
err = krb5_cc_end_seq_get(context, ccache, &cursor);
|
|
Packit Service |
9f2c4a |
if (err != 0) {
|
|
Packit Service |
9f2c4a |
ret_min = err;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
if (context) {
|
|
Packit Service |
9f2c4a |
/* NOTE: destroy only if we created a MEMORY ccache */
|
|
Packit Service |
9f2c4a |
if (ccache) {
|
|
Packit Service |
9f2c4a |
if (memcache) {
|
|
Packit Service |
9f2c4a |
krb5_cc_destroy(context, ccache);
|
|
Packit Service |
9f2c4a |
} else {
|
|
Packit Service |
9f2c4a |
krb5_cc_close(context, ccache);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
krb5_free_context(context);
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
free(memcache);
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
/* Check if cred refresh is being requested by the client.
|
|
Packit Service |
9f2c4a |
* if so, take a snapshot of the cred so that later we can check if anything
|
|
Packit Service |
9f2c4a |
* was added */
|
|
Packit Service |
9f2c4a |
uint32_t gp_check_sync_creds(struct gp_cred_check_handle *h,
|
|
Packit Service |
9f2c4a |
gss_cred_id_t cred)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
struct gp_service *svc = h->ctx->service;
|
|
Packit Service |
9f2c4a |
struct gssx_option *opt = NULL;
|
|
Packit Service |
9f2c4a |
uint32_t ccsum = 0;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
if (!svc->allow_cc_sync)
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
gp_options_find(opt, h->options, CRED_SYNC_OPTION,
|
|
Packit Service |
9f2c4a |
sizeof(CRED_SYNC_OPTION));
|
|
Packit Service |
9f2c4a |
if (!opt) {
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
if (!gpopt_string_match(&opt->value, CRED_SYNC_DEFAULT,
|
|
Packit Service |
9f2c4a |
sizeof(CRED_SYNC_DEFAULT))) {
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
for (size_t i = 0; i < svc->krb5.store.count; i++) {
|
|
Packit Service |
9f2c4a |
if (strcmp(svc->krb5.store.elements[i].key, "ccache") == 0) {
|
|
Packit Service |
9f2c4a |
/* Saving in local ccache no need to sync up to client */
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gp_count_tickets(&ret_min, cred, &ccsum);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
return 0;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
return ccsum;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
uint32_t gp_export_sync_creds(uint32_t *min, struct gp_call_ctx *gpcall,
|
|
Packit Service |
9f2c4a |
gss_cred_id_t *cred,
|
|
Packit Service |
9f2c4a |
gssx_option **options_val, u_int *options_len)
|
|
Packit Service |
9f2c4a |
{
|
|
Packit Service |
9f2c4a |
uint32_t ret_maj = 0;
|
|
Packit Service |
9f2c4a |
uint32_t ret_min = 0;
|
|
Packit Service |
9f2c4a |
gssx_cred creds = { 0 };
|
|
Packit Service |
9f2c4a |
char value[GPKRB_MAX_CRED_SIZE];
|
|
Packit Service |
9f2c4a |
size_t len;
|
|
Packit Service |
9f2c4a |
XDR xdrctx;
|
|
Packit Service |
9f2c4a |
bool xdrok;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_maj = gp_export_gssx_cred(&ret_min, gpcall, cred, &creds);
|
|
Packit Service |
9f2c4a |
if (ret_maj) {
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
xdrmem_create(&xdrctx, value, GPKRB_MAX_CRED_SIZE, XDR_ENCODE);
|
|
Packit Service |
9f2c4a |
xdrok = xdr_gssx_cred(&xdrctx, &creds);
|
|
Packit Service |
9f2c4a |
if (!xdrok) {
|
|
Packit Service |
9f2c4a |
ret_min = ENOSPC;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
len = xdr_getpos(&xdrctx);
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_min = gp_add_option(options_val, options_len, CRED_SYNC_PAYLOAD,
|
|
Packit Service |
9f2c4a |
sizeof(CRED_SYNC_PAYLOAD), value, len);
|
|
Packit Service |
9f2c4a |
if (ret_min) {
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_FAILURE;
|
|
Packit Service |
9f2c4a |
goto done;
|
|
Packit Service |
9f2c4a |
}
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
ret_min = 0;
|
|
Packit Service |
9f2c4a |
ret_maj = GSS_S_COMPLETE;
|
|
Packit Service |
9f2c4a |
|
|
Packit Service |
9f2c4a |
done:
|
|
Packit Service |
9f2c4a |
xdr_free((xdrproc_t)xdr_gssx_cred, (char *)&creds);
|
|
Packit Service |
9f2c4a |
*min = ret_min;
|
|
Packit Service |
9f2c4a |
return ret_maj;
|
|
Packit Service |
9f2c4a |
}
|