kgssapi: Fix the kgssapi so that it can use MIT Kerberos

Without this patch, the kgssapi uses detailed knowledge
of the internal context structure for Heimdal (up to vers 1.5).
It also does four upcalls to the gssd daemon to establish
a server side RPCSEC_GSS context.

This patch adds support for three new upcalls:
gss_init_sec_context_lucid_v1()
gss_accept_sec_context_lucid_v1()
gss_supports_lucid()

These are used to determine if the gssd can do the upcalls
and uses them to avoid needing detailed Heimdal knowledge
if they are supported.

gss_init_sec_context_lucid_v1() and
gss_accept_sec_context_lucid_v1() return the information
needed to complete the RPCSEC_GSS context.
They use gss_krb5_export_lucid_sec_context() to acquire
the information from the libraries. (MIT Kerberos supports
this and I believe newer versions of Heimdal does, as well).

This avoids the need for detailed knowledge about MIT's
internals and replaces the 2 or 4 (initiator or acceptor) upcalls
with a single upcall to create the RPCSEC_GSS context.

The old Heimdal (up to 1.5) support is left intact, but should
be removed whenever Heimdal 1.5 is removed from /usr/src.

It also modifies the Makefile so that the gssd is only built
when MK_KERBEROS_SUPPORT != "no", since it is useless without
Kerberos.

Reviewed by:	cy
Differeential Revision:	https://reviews.freebsd.org/D51731
Differeential Revision:	https://reviews.freebsd.org/D51733
This commit is contained in:
Rick Macklem 2025-08-07 14:02:32 -07:00
parent 42cacae4eb
commit e3ac01e18e
13 changed files with 1105 additions and 83 deletions

View file

@ -41,6 +41,11 @@
#include "gssd.h"
#include "kgss_if.h"
/*
* This function should only be called when the gssd
* daemon running on the system is an old one that
* does not use gss_krb5_export_lucid_sec_context().
*/
OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
const gss_cred_id_t acceptor_cred_handle,
@ -138,7 +143,145 @@ OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
* etc.) to the kernel implementation.
*/
if (res.major_status == GSS_S_COMPLETE)
res.major_status = kgss_transfer_context(ctx);
res.major_status = kgss_transfer_context(ctx, NULL);
return (res.major_status);
}
/*
* This function should be called when the gssd daemon is
* one that uses gss_krb5_export_lucid_sec_context().
* There is a lot of code common with
* gss_accept_sec_context(). However, the structures used
* are not the same and future changes may be needed for
* this one. As such, I have not factored out the common
* code.
* gss_supports_lucid() may be used to check to see if the
* gssd daemon uses gss_krb5_export_lucid_sec_context().
*/
OM_uint32 gss_accept_sec_context_lucid_v1(OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
const gss_cred_id_t acceptor_cred_handle,
const gss_buffer_t input_token,
const gss_channel_bindings_t input_chan_bindings,
gss_name_t *src_name,
gss_OID *mech_type,
gss_buffer_t output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec,
gss_cred_id_t *delegated_cred_handle,
gss_buffer_t exported_name,
uid_t *uidp,
gid_t *gidp,
int *numgroups,
gid_t *groups)
{
struct accept_sec_context_lucid_v1_res res;
struct accept_sec_context_lucid_v1_args args;
enum clnt_stat stat;
gss_ctx_id_t ctx = *context_handle;
gss_name_t name;
gss_cred_id_t cred;
CLIENT *cl;
cl = kgss_gssd_client();
if (cl == NULL) {
*minor_status = 0;
return (GSS_S_FAILURE);
}
if (ctx)
args.ctx = ctx->handle;
else
args.ctx = 0;
if (acceptor_cred_handle)
args.cred = acceptor_cred_handle->handle;
else
args.cred = 0;
args.input_token = *input_token;
args.input_chan_bindings = input_chan_bindings;
bzero(&res, sizeof(res));
stat = gssd_accept_sec_context_lucid_v1_1(&args, &res, cl);
CLNT_RELEASE(cl);
if (stat != RPC_SUCCESS) {
*minor_status = stat;
return (GSS_S_FAILURE);
}
if (res.major_status != GSS_S_COMPLETE
&& res.major_status != GSS_S_CONTINUE_NEEDED) {
*minor_status = res.minor_status;
xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
return (res.major_status);
}
*minor_status = res.minor_status;
if (!ctx) {
ctx = kgss_create_context(res.mech_type);
if (!ctx) {
xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
*minor_status = 0;
return (GSS_S_BAD_MECH);
}
}
*context_handle = ctx;
ctx->handle = res.ctx;
name = malloc(sizeof(struct _gss_name_t), M_GSSAPI, M_WAITOK);
name->handle = res.src_name;
if (src_name) {
*src_name = name;
} else {
OM_uint32 junk;
gss_release_name(&junk, &name);
}
if (mech_type)
*mech_type = KGSS_MECH_TYPE(ctx);
kgss_copy_buffer(&res.output_token, output_token);
if (ret_flags)
*ret_flags = res.ret_flags;
if (time_rec)
*time_rec = res.time_rec;
cred = malloc(sizeof(struct _gss_cred_id_t), M_GSSAPI, M_WAITOK);
cred->handle = res.delegated_cred_handle;
if (delegated_cred_handle) {
*delegated_cred_handle = cred;
} else {
OM_uint32 junk;
gss_release_cred(&junk, &cred);
}
/*
* If the context establishment is complete, export it from
* userland and hand the result (which includes key material
* etc.) to the kernel implementation.
*/
if (res.major_status == GSS_S_COMPLETE) {
int i, n;
/* First, get the unix credentials. */
*uidp = res.uid;
*gidp = res.gid;
n = res.gidlist.gidlist_len;
if (n > *numgroups)
n = *numgroups;
for (i = 0; i < n; i++)
groups[i] = res.gidlist.gidlist_val[i];
*numgroups = n;
/* Next, get the exported_name. */
kgss_copy_buffer(&res.exported_name, exported_name);
/* Now, handle the lucid credential setup. */
res.major_status = kgss_transfer_context(ctx, &res.lucid);
if (res.major_status != GSS_S_COMPLETE)
printf("gss_accept_sec_context_lucid_v1: "
"transfer failed\n");
}
xdr_free((xdrproc_t) xdr_accept_sec_context_res, &res);
return (res.major_status);
}

View file

@ -192,13 +192,19 @@ kgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token)
}
OM_uint32
kgss_transfer_context(gss_ctx_id_t ctx)
kgss_transfer_context(gss_ctx_id_t ctx, void *lctx)
{
struct export_sec_context_res res;
struct export_sec_context_args args;
enum clnt_stat stat;
OM_uint32 maj_stat;
if (lctx != NULL) {
maj_stat = KGSS_IMPORT(ctx, MIT_V1, lctx);
ctx->handle = 0;
return (maj_stat);
}
KGSS_CURVNET_SET_QUIET(KGSS_TD_TO_VNET(curthread));
if (!KGSS_VNET(kgss_gssd_handle)) {
KGSS_CURVNET_RESTORE();

View file

@ -42,6 +42,11 @@
#include "gssd.h"
#include "kgss_if.h"
/*
* This function should only be called when the gssd
* daemon running on the system is an old one that
* does not use gss_krb5_export_lucid_sec_context().
*/
OM_uint32
gss_init_sec_context(OM_uint32 * minor_status,
const gss_cred_id_t initiator_cred_handle,
@ -133,7 +138,145 @@ gss_init_sec_context(OM_uint32 * minor_status,
* etc.) to the kernel implementation.
*/
if (res.major_status == GSS_S_COMPLETE)
res.major_status = kgss_transfer_context(ctx);
res.major_status = kgss_transfer_context(ctx, NULL);
return (res.major_status);
}
OM_uint32
gss_supports_lucid(uint32_t *minor_status, uint32_t *vers)
{
struct supports_lucid_res res;
enum clnt_stat stat;
CLIENT *cl;
*minor_status = 0;
cl = kgss_gssd_client();
if (cl == NULL)
return (GSS_S_FAILURE);
bzero(&res, sizeof(res));
stat = gssd_supports_lucid_1(NULL, &res, cl);
CLNT_RELEASE(cl);
if (stat != RPC_SUCCESS) {
*minor_status = stat;
return (GSS_S_FAILURE);
}
if (vers)
*vers = res.vers;
return (res.major_status);
}
/*
* This function should be called when the gssd daemon is
* one that uses gss_krb5_export_lucid_sec_context().
* There is a lot of code common with
* gss_init_sec_context(). However, the structures used
* are not the same and future changes may be needed for
* this one. As such, I have not factored out the common
* code.
* gss_supports_lucid() may be used to check to see if the
* gssd daemon uses gss_krb5_export_lucid_sec_context().
*/
OM_uint32
gss_init_sec_context_lucid_v1(OM_uint32 * minor_status,
const gss_cred_id_t initiator_cred_handle,
gss_ctx_id_t * context_handle,
const gss_name_t target_name,
const gss_OID input_mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
const gss_channel_bindings_t input_chan_bindings,
const gss_buffer_t input_token,
gss_OID * actual_mech_type,
gss_buffer_t output_token,
OM_uint32 * ret_flags,
OM_uint32 * time_rec)
{
struct init_sec_context_lucid_v1_res res;
struct init_sec_context_lucid_v1_args args;
enum clnt_stat stat;
gss_ctx_id_t ctx = *context_handle;
CLIENT *cl;
*minor_status = 0;
cl = kgss_gssd_client();
if (cl == NULL)
return (GSS_S_FAILURE);
args.uid = curthread->td_ucred->cr_uid;
if (initiator_cred_handle)
args.cred = initiator_cred_handle->handle;
else
args.cred = 0;
if (ctx)
args.ctx = ctx->handle;
else
args.ctx = 0;
args.name = target_name->handle;
args.mech_type = input_mech_type;
args.req_flags = req_flags;
args.time_req = time_req;
args.input_chan_bindings = input_chan_bindings;
if (input_token)
args.input_token = *input_token;
else {
args.input_token.length = 0;
args.input_token.value = NULL;
}
bzero(&res, sizeof(res));
stat = gssd_init_sec_context_lucid_v1_1(&args, &res, cl);
CLNT_RELEASE(cl);
if (stat != RPC_SUCCESS) {
*minor_status = stat;
return (GSS_S_FAILURE);
}
if (res.major_status != GSS_S_COMPLETE
&& res.major_status != GSS_S_CONTINUE_NEEDED) {
*minor_status = res.minor_status;
xdr_free((xdrproc_t) xdr_init_sec_context_lucid_v1_res, &res);
return (res.major_status);
}
*minor_status = res.minor_status;
if (!ctx) {
ctx = kgss_create_context(res.actual_mech_type);
if (!ctx) {
xdr_free((xdrproc_t) xdr_init_sec_context_lucid_v1_res, &res);
*minor_status = 0;
return (GSS_S_BAD_MECH);
}
}
*context_handle = ctx;
ctx->handle = res.ctx;
if (actual_mech_type)
*actual_mech_type = KGSS_MECH_TYPE(ctx);
kgss_copy_buffer(&res.output_token, output_token);
if (ret_flags)
*ret_flags = res.ret_flags;
if (time_rec)
*time_rec = res.time_rec;
/*
* If the context establishment is complete, export it from
* userland and hand the result (which includes key material
* etc.) to the kernel implementation.
*/
if (res.major_status == GSS_S_COMPLETE) {
res.major_status = kgss_transfer_context(ctx, &res.lucid);
if (res.major_status != GSS_S_COMPLETE)
printf("gss_init_sec_context_lucid_v1: "
"transfer failed\n");
}
xdr_free((xdrproc_t) xdr_init_sec_context_lucid_v1_res, &res);
return (res.major_status);
}

View file

@ -422,6 +422,28 @@ OM_uint32 gss_init_sec_context
OM_uint32 * /* time_rec */
);
OM_uint32 gss_init_sec_context_lucid_v1
(OM_uint32 *, /* minor_status */
const gss_cred_id_t, /* initiator_cred_handle */
gss_ctx_id_t *, /* context_handle */
const gss_name_t, /* target_name */
const gss_OID, /* mech_type */
OM_uint32, /* req_flags */
OM_uint32, /* time_req */
const gss_channel_bindings_t,
/* input_chan_bindings */
const gss_buffer_t, /* input_token */
gss_OID *, /* actual_mech_type */
gss_buffer_t, /* output_token */
OM_uint32 *, /* ret_flags */
OM_uint32 * /* time_rec */
);
OM_uint32 gss_supports_lucid
(OM_uint32 *, /* minor_status */
OM_uint32 * /* vers */
);
OM_uint32 gss_accept_sec_context
(OM_uint32 *, /* minor_status */
gss_ctx_id_t *, /* context_handle */
@ -437,6 +459,26 @@ OM_uint32 gss_accept_sec_context
gss_cred_id_t * /* delegated_cred_handle */
);
OM_uint32 gss_accept_sec_context_lucid_v1
(OM_uint32 *, /* minor_status */
gss_ctx_id_t *, /* context_handle */
const gss_cred_id_t, /* acceptor_cred_handle */
const gss_buffer_t, /* input_token_buffer */
const gss_channel_bindings_t,
/* input_chan_bindings */
gss_name_t *, /* src_name */
gss_OID *, /* mech_type */
gss_buffer_t, /* output_token */
OM_uint32 *, /* ret_flags */
OM_uint32 *, /* time_rec */
gss_cred_id_t *, /* delegated_cred_handle */
gss_buffer_t, /* exported_name */
uid_t *, /* Unix cred */
gid_t *,
int *, /* Number of groups */
gid_t * /* groups list */
);
OM_uint32 gss_delete_sec_context
(OM_uint32 *, /* minor_status */
gss_ctx_id_t *, /* context_handle */

View file

@ -78,5 +78,5 @@ extern gss_OID kgss_find_mech_by_name(const char *name);
extern const char *kgss_find_mech_by_oid(const gss_OID oid);
extern gss_ctx_id_t kgss_create_context(gss_OID mech_type);
extern void kgss_delete_context(gss_ctx_id_t ctx, gss_buffer_t output_token);
extern OM_uint32 kgss_transfer_context(gss_ctx_id_t ctx);
extern OM_uint32 kgss_transfer_context(gss_ctx_id_t ctx, void *lctx);
extern void kgss_copy_buffer(const gss_buffer_t from, gss_buffer_t to);

View file

@ -48,6 +48,21 @@ typedef uint64_t gssd_ctx_id_t;
typedef uint64_t gssd_cred_id_t;
typedef uint64_t gssd_name_t;
struct kgss_lucid_desc {
uint32_t initiate;
uint32_t endtime;
uint64_t send_seq;
uint64_t recv_seq;
uint32_t protocol;
uint32_t rfc_sign;
uint32_t rfc_seal;
uint32_t have_subkey;
uint32_t ctx_type;
gss_buffer_desc ctx_key;
uint32_t subkey_type;
gss_buffer_desc subkey_key;
};
struct init_sec_context_res {
uint32_t major_status;
uint32_t minor_status;
@ -70,6 +85,29 @@ struct init_sec_context_args {
gss_buffer_desc input_token;
};
struct init_sec_context_lucid_v1_res {
uint32_t major_status;
uint32_t minor_status;
gssd_ctx_id_t ctx;
gss_OID actual_mech_type;
gss_buffer_desc output_token;
uint32_t ret_flags;
uint32_t time_rec;
kgss_lucid_desc lucid;
};
struct init_sec_context_lucid_v1_args {
uint32_t uid;
gssd_cred_id_t cred;
gssd_ctx_id_t ctx;
gssd_name_t name;
gss_OID mech_type;
uint32_t req_flags;
uint32_t time_req;
gss_channel_bindings_t input_chan_bindings;
gss_buffer_desc input_token;
};
struct accept_sec_context_res {
uint32_t major_status;
uint32_t minor_status;
@ -89,6 +127,30 @@ struct accept_sec_context_args {
gss_channel_bindings_t input_chan_bindings;
};
struct accept_sec_context_lucid_v1_res {
uint32_t major_status;
uint32_t minor_status;
gssd_ctx_id_t ctx;
gssd_name_t src_name;
gss_OID mech_type;
gss_buffer_desc output_token;
uint32_t ret_flags;
uint32_t time_rec;
gssd_cred_id_t delegated_cred_handle;
kgss_lucid_desc lucid;
gss_buffer_desc exported_name;
uint32_t uid;
uint32_t gid;
uint32_t gidlist<>;
};
struct accept_sec_context_lucid_v1_args {
gssd_ctx_id_t ctx;
gssd_cred_id_t cred;
gss_buffer_desc input_token;
gss_channel_bindings_t input_chan_bindings;
};
struct delete_sec_context_res {
uint32_t major_status;
uint32_t minor_status;
@ -101,7 +163,8 @@ struct delete_sec_context_args {
enum sec_context_format {
KGSS_HEIMDAL_0_6,
KGSS_HEIMDAL_1_1
KGSS_HEIMDAL_1_1,
MIT_V1
};
struct export_sec_context_res {
@ -229,6 +292,11 @@ struct ip_to_dns_args {
char ip_addr<NI_MAXHOST>;
};
struct supports_lucid_res {
uint32_t major_status;
uint32_t vers;
};
program GSSD {
version GSSDVERS {
void GSSD_NULL(void) = 0;
@ -274,5 +342,14 @@ program GSSD {
ip_to_dns_res
GSSD_IP_TO_DNS(ip_to_dns_args) = 14;
init_sec_context_lucid_v1_res
GSSD_INIT_SEC_CONTEXT_LUCID_V1(init_sec_context_lucid_v1_args) = 15;
accept_sec_context_lucid_v1_res
GSSD_ACCEPT_SEC_CONTEXT_LUCID_V1(accept_sec_context_lucid_v1_args) = 16;
supports_lucid_res
GSSD_SUPPORTS_LUCID(void) = 17;
} = 1;
} = 0x40677373;

View file

@ -217,6 +217,18 @@ copy_key(struct krb5_keyblock *from, struct krb5_keyblock **to)
*to = NULL;
}
static void
copy_lucid_key(gss_buffer_desc *from, uint32_t type, struct krb5_keyblock *to)
{
to->kk_type = type;
to->kk_key.kd_length = from->length;
if (from->length > 0) {
to->kk_key.kd_data = malloc(from->length, M_GSSAPI, M_WAITOK);
memcpy(to->kk_key.kd_data, from->value, from->length);
}
}
/*
* Return non-zero if we are initiator.
*/
@ -401,6 +413,70 @@ krb5_init(gss_ctx_id_t ctx)
mtx_init(&kc->kc_lock, "krb5 gss lock", NULL, MTX_DEF);
}
static OM_uint32
krb5_lucid_import(gss_ctx_id_t ctx,
enum sec_context_format format,
const gss_buffer_t context_token)
{
struct krb5_context *kc = (struct krb5_context *)ctx;
kgss_lucid_desc *lctx = (kgss_lucid_desc *)context_token;
OM_uint32 res;
kc->kc_more_flags = 0;
if (lctx->protocol == 0) {
kc->kc_cksumtype = lctx->rfc_sign;
kc->kc_keytype = lctx->rfc_seal;
copy_lucid_key(&lctx->ctx_key, lctx->ctx_type,
&kc->kc_keyblock);
} else if (lctx->protocol == 1) {
if (lctx->have_subkey != 0) {
if (lctx->initiate != 0)
copy_lucid_key(&lctx->subkey_key,
lctx->subkey_type,
&kc->kc_remote_subkey);
else
copy_lucid_key(&lctx->subkey_key,
lctx->subkey_type,
&kc->kc_local_subkey);
kc->kc_cksumtype = lctx->subkey_type;
kc->kc_keytype = lctx->subkey_type;
kc->kc_more_flags |= ACCEPTOR_SUBKEY;
} else {
if (lctx->initiate != 0)
copy_lucid_key(&lctx->ctx_key,
lctx->ctx_type,
&kc->kc_remote_subkey);
else
copy_lucid_key(&lctx->ctx_key,
lctx->ctx_type,
&kc->kc_local_subkey);
kc->kc_cksumtype = lctx->ctx_type;
kc->kc_keytype = lctx->ctx_type;
}
} else {
return (GSS_S_DEFECTIVE_TOKEN);
}
kc->kc_local_seqnumber = lctx->send_seq;
kc->kc_remote_seqnumber = lctx->recv_seq;
if (lctx->initiate != 0)
kc->kc_more_flags |= LOCAL;
kc->kc_lifetime = lctx->endtime;
kc->kc_msg_order.km_flags = 0;
res = get_keys(kc);
if (GSS_ERROR(res))
return (res);
/*
* We don't need these anymore.
*/
delete_keyblock(&kc->kc_keyblock);
delete_keyblock(&kc->kc_local_subkey);
delete_keyblock(&kc->kc_remote_subkey);
return (GSS_S_COMPLETE);
}
static OM_uint32
krb5_import(gss_ctx_id_t ctx,
enum sec_context_format format,
@ -413,6 +489,10 @@ krb5_import(gss_ctx_id_t ctx,
uint32_t flags;
int i;
/* For MIT, just call krb5_lucid_import(). */
if (format == MIT_V1)
return (krb5_lucid_import(ctx, format, context_token));
/*
* We support heimdal 0.6 and heimdal 1.1
*/

View file

@ -746,6 +746,7 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
struct rpc_callextra ext;
gss_OID mech_oid;
gss_OID_set mechlist;
static enum krb_imp my_krb_imp = KRBIMP_UNKNOWN;
rpc_gss_log_debug("in rpc_gss_refresh()");
@ -852,6 +853,14 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
goto out;
}
if (my_krb_imp == KRBIMP_UNKNOWN) {
maj_stat = gss_supports_lucid(&min_stat, NULL);
if (maj_stat == GSS_S_COMPLETE)
my_krb_imp = KRBIMP_MIT;
else
my_krb_imp = KRBIMP_HESIOD1;
}
/* GSS context establishment loop. */
memset(&recv_token, 0, sizeof(recv_token));
memset(&gr, 0, sizeof(gr));
@ -862,19 +871,34 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
for (;;) {
crsave = td->td_ucred;
td->td_ucred = gd->gd_ucred;
maj_stat = gss_init_sec_context(&min_stat,
gd->gd_options.my_cred,
&gd->gd_ctx,
name,
gd->gd_mech,
gd->gd_options.req_flags,
gd->gd_options.time_req,
gd->gd_options.input_channel_bindings,
recv_tokenp,
&gd->gd_mech, /* used mech */
&send_token,
&options_ret->ret_flags,
&options_ret->time_req);
if (my_krb_imp == KRBIMP_MIT)
maj_stat = gss_init_sec_context_lucid_v1(&min_stat,
gd->gd_options.my_cred,
&gd->gd_ctx,
name,
gd->gd_mech,
gd->gd_options.req_flags,
gd->gd_options.time_req,
gd->gd_options.input_channel_bindings,
recv_tokenp,
&gd->gd_mech, /* used mech */
&send_token,
&options_ret->ret_flags,
&options_ret->time_req);
else
maj_stat = gss_init_sec_context(&min_stat,
gd->gd_options.my_cred,
&gd->gd_ctx,
name,
gd->gd_mech,
gd->gd_options.req_flags,
gd->gd_options.time_req,
gd->gd_options.input_channel_bindings,
recv_tokenp,
&gd->gd_mech, /* used mech */
&send_token,
&options_ret->ret_flags,
&options_ret->time_req);
td->td_ucred = crsave;
/*

View file

@ -73,6 +73,12 @@ struct rpc_gss_init_res {
/* Maximum sequence number value. */
#define MAXSEQ 0x80000000
enum krb_imp {
KRBIMP_UNKNOWN,
KRBIMP_HESIOD1,
KRBIMP_MIT
};
/* Prototypes. */
__BEGIN_DECLS

View file

@ -925,9 +925,29 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client,
OM_uint32 maj_stat = 0, min_stat = 0, ret_flags;
OM_uint32 cred_lifetime;
struct svc_rpc_gss_svc_name *sname;
gss_buffer_desc export_name;
rpc_gss_ucred_t *uc = &client->cl_ucred;
int numgroups;
static enum krb_imp my_krb_imp = KRBIMP_UNKNOWN;
rpc_gss_log_debug("in svc_rpc_gss_accept_context()");
if (my_krb_imp == KRBIMP_UNKNOWN) {
maj_stat = gss_supports_lucid(&min_stat, NULL);
if (maj_stat == GSS_S_COMPLETE)
my_krb_imp = KRBIMP_MIT;
else
my_krb_imp = KRBIMP_HESIOD1;
min_stat = 0;
}
if (my_krb_imp == KRBIMP_MIT) {
uc->uid = 65534;
uc->gid = 65534;
uc->gidlist = client->cl_gid_storage;
numgroups = NGROUPS;
}
/* Deserialize arguments. */
memset(&recv_tok, 0, sizeof(recv_tok));
@ -949,18 +969,38 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client,
if (sname->sn_program == rqst->rq_prog
&& sname->sn_version == rqst->rq_vers) {
retry:
gr->gr_major = gss_accept_sec_context(
&gr->gr_minor,
&client->cl_ctx,
sname->sn_cred,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client->cl_cname,
&mech,
&gr->gr_token,
&ret_flags,
&cred_lifetime,
&client->cl_creds);
if (my_krb_imp == KRBIMP_MIT)
gr->gr_major =
gss_accept_sec_context_lucid_v1(
&gr->gr_minor,
&client->cl_ctx,
sname->sn_cred,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client->cl_cname,
&mech,
&gr->gr_token,
&ret_flags,
&cred_lifetime,
&client->cl_creds,
&export_name,
&uc->uid,
&uc->gid,
&numgroups,
&uc->gidlist[0]);
else
gr->gr_major = gss_accept_sec_context(
&gr->gr_minor,
&client->cl_ctx,
sname->sn_cred,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client->cl_cname,
&mech,
&gr->gr_token,
&ret_flags,
&cred_lifetime,
&client->cl_creds);
if (gr->gr_major ==
GSS_S_CREDENTIALS_EXPIRED) {
/*
@ -982,18 +1022,37 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client,
return (FALSE);
}
} else {
gr->gr_major = gss_accept_sec_context(
&gr->gr_minor,
&client->cl_ctx,
client->cl_sname->sn_cred,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client->cl_cname,
&mech,
&gr->gr_token,
&ret_flags,
&cred_lifetime,
NULL);
if (my_krb_imp == KRBIMP_MIT)
gr->gr_major = gss_accept_sec_context_lucid_v1(
&gr->gr_minor,
&client->cl_ctx,
client->cl_sname->sn_cred,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client->cl_cname,
&mech,
&gr->gr_token,
&ret_flags,
&cred_lifetime,
NULL,
&export_name,
&uc->uid,
&uc->gid,
&numgroups,
&uc->gidlist[0]);
else
gr->gr_major = gss_accept_sec_context(
&gr->gr_minor,
&client->cl_ctx,
client->cl_sname->sn_cred,
&recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&client->cl_cname,
&mech,
&gr->gr_token,
&ret_flags,
&cred_lifetime,
NULL);
}
sx_xunlock(&svc_rpc_gss_lock);
@ -1009,8 +1068,12 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client,
rpc_gss_log_status("accept_sec_context", client->cl_mech,
gr->gr_major, gr->gr_minor);
client->cl_state = CLIENT_STALE;
if (my_krb_imp == KRBIMP_MIT)
uc->gidlen = 0;
return (TRUE);
}
if (my_krb_imp == KRBIMP_MIT)
uc->gidlen = numgroups;
gr->gr_handle.value = &client->cl_id;
gr->gr_handle.length = sizeof(client->cl_id);
@ -1022,8 +1085,6 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client,
client->cl_done_callback = FALSE;
if (gr->gr_major == GSS_S_COMPLETE) {
gss_buffer_desc export_name;
/*
* Change client expiration time to be near when the
* client creds expire (or 24 hours if we can't figure
@ -1046,8 +1107,10 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client,
*/
client->cl_rawcred.version = RPCSEC_GSS_VERSION;
rpc_gss_oid_to_mech(mech, &client->cl_rawcred.mechanism);
maj_stat = gss_export_name(&min_stat, client->cl_cname,
&export_name);
maj_stat = GSS_S_COMPLETE;
if (my_krb_imp != KRBIMP_MIT)
maj_stat = gss_export_name(&min_stat, client->cl_cname,
&export_name);
if (maj_stat != GSS_S_COMPLETE) {
rpc_gss_log_status("gss_export_name", client->cl_mech,
maj_stat, min_stat);
@ -1068,7 +1131,8 @@ svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client,
* Use gss_pname_to_uid to map to unix creds. For
* kerberos5, this uses krb5_aname_to_localname.
*/
svc_rpc_gss_build_ucred(client, client->cl_cname);
if (my_krb_imp != KRBIMP_MIT)
svc_rpc_gss_build_ucred(client, client->cl_cname);
svc_rpc_gss_set_flavor(client);
gss_release_name(&min_stat, &client->cl_cname);

View file

@ -140,7 +140,9 @@ SUBDIR.${MK_FLOPPY}+= fdformat
SUBDIR.${MK_FLOPPY}+= fdread
SUBDIR.${MK_FLOPPY}+= fdwrite
SUBDIR.${MK_FREEBSD_UPDATE}+= freebsd-update
.if ${MK_KERBEROS_SUPPORT} != "no"
SUBDIR.${MK_GSSAPI}+= gssd
.endif
SUBDIR.${MK_GPIO}+= gpioctl
SUBDIR.${MK_HYPERV}+= hyperv
SUBDIR.${MK_INET6}+= ip6addrctl

View file

@ -9,7 +9,6 @@ SRCS= gssd.c gssd.h gssd_svc.c gssd_xdr.c gssd_prot.c
CFLAGS+= -I.
WARNS?= 1
.if ${MK_KERBEROS_SUPPORT} != "no"
.if ${MK_MITKRB5} != "no"
# MIT KRB5
LIBADD+= gssapi_krb5 krb5 k5crypto krb5profile krb5support
@ -18,9 +17,6 @@ CFLAGS+= -DMK_MITKRB5=yes
# Heimdal
LIBADD+= gssapi krb5 roken
.endif
.else
CFLAGS+= -DWITHOUT_KERBEROS
.endif
CLEANFILES= gssd_svc.c gssd_xdr.c gssd.h

View file

@ -39,9 +39,7 @@
#include <dirent.h>
#include <err.h>
#include <errno.h>
#ifndef WITHOUT_KERBEROS
#include <krb5.h>
#endif
#include <netdb.h>
#include <pwd.h>
#include <signal.h>
@ -80,7 +78,6 @@ static char ccfile_dirlist[PATH_MAX + 1], ccfile_substring[NAME_MAX + 1];
static char pref_realm[1024];
static int verbose;
static int hostbased_initiator_cred;
#ifndef WITHOUT_KERBEROS
/* 1.2.752.43.13.14 */
static gss_OID_desc gss_krb5_set_allowable_enctypes_x_desc =
{6, (void *) "\x2a\x85\x70\x2b\x0d\x0e"};
@ -90,16 +87,13 @@ static gss_OID_desc gss_krb5_mech_oid_x_desc =
{9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
static gss_OID GSS_KRB5_MECH_OID_X =
&gss_krb5_mech_oid_x_desc;
#endif
static void gssd_load_mech(void);
static int find_ccache_file(const char *, uid_t, char *);
static int is_a_valid_tgt_cache(const char *, uid_t, int *, time_t *);
static void gssd_verbose_out(const char *, ...);
#ifndef WITHOUT_KERBEROS
static krb5_error_code gssd_get_cc_from_keytab(const char *);
static OM_uint32 gssd_get_user_cred(OM_uint32 *, uid_t, gss_cred_id_t *);
#endif
void gssd_terminate(int);
extern void gssd_1(struct svc_req *rqstp, SVCXPRT *transp);
@ -131,32 +125,22 @@ main(int argc, char **argv)
debug_level++;
break;
case 'h':
#ifndef WITHOUT_KERBEROS
/*
* Enable use of a host based initiator credential
* in the default keytab file.
*/
hostbased_initiator_cred = 1;
#else
errx(1, "This option not available when built"
" without MK_KERBEROS\n");
#endif
break;
case 'v':
verbose = 1;
break;
case 's':
#ifndef WITHOUT_KERBEROS
/*
* Set the directory search list. This enables use of
* find_ccache_file() to search the directories for a
* suitable credentials cache file.
*/
strlcpy(ccfile_dirlist, optarg, sizeof(ccfile_dirlist));
#else
errx(1, "This option not available when built"
" without MK_KERBEROS\n");
#endif
break;
case 'c':
/*
@ -338,6 +322,7 @@ gssd_null_1_svc(void *argp, void *result, struct svc_req *rqstp)
return (TRUE);
}
#ifndef MK_MITKRB5
bool_t
gssd_init_sec_context_1_svc(init_sec_context_args *argp, init_sec_context_res *result, struct svc_req *rqstp)
{
@ -347,12 +332,10 @@ gssd_init_sec_context_1_svc(init_sec_context_args *argp, init_sec_context_res *r
char ccname[PATH_MAX + 5 + 1], *cp, *cp2;
int gotone, gotcred;
OM_uint32 min_stat;
#ifndef WITHOUT_KERBEROS
gss_buffer_desc principal_desc;
char enctype[sizeof(uint32_t)];
int key_enctype;
OM_uint32 maj_stat;
#endif
memset(result, 0, sizeof(*result));
if (hostbased_initiator_cred != 0 && argp->cred != 0 &&
@ -461,6 +444,35 @@ gssd_init_sec_context_1_svc(init_sec_context_args *argp, init_sec_context_res *r
return (TRUE);
}
bool_t
gssd_supports_lucid_1_svc(void *argp, supports_lucid_res *result, struct svc_req *rqstp)
{
gssd_verbose_out("gssd_lucid: done\n");
result->major_status = GSS_S_UNAVAILABLE;
return (TRUE);
}
bool_t
gssd_init_sec_context_lucid_v1_1_svc(init_sec_context_lucid_v1_args *argp,
init_sec_context_lucid_v1_res *result, struct svc_req *rqstp)
{
gssd_verbose_out("gssd_init_sec_context_lucid_v1: Heimdal\n");
result->major_status = GSS_S_UNAVAILABLE;
return (TRUE);
}
bool_t
gssd_accept_sec_context_lucid_v1_1_svc(accept_sec_context_lucid_v1_args *argp,
accept_sec_context_lucid_v1_res *result, struct svc_req *rqstp)
{
gssd_verbose_out("gssd_accept_sec_context_lucid_v1: Heimdal\n");
result->major_status = GSS_S_UNAVAILABLE;
return (TRUE);
}
bool_t
gssd_accept_sec_context_1_svc(accept_sec_context_args *argp, accept_sec_context_res *result, struct svc_req *rqstp)
{
@ -511,6 +523,446 @@ gssd_accept_sec_context_1_svc(accept_sec_context_args *argp, accept_sec_context_
return (TRUE);
}
#else /* MK_MITKRB5 */
bool_t
gssd_supports_lucid_1_svc(void *argp, supports_lucid_res *result, struct svc_req *rqstp)
{
gssd_verbose_out("gssd_lucid: done\n");
result->vers = 1;
result->major_status = GSS_S_COMPLETE;
return (TRUE);
}
bool_t
gssd_init_sec_context_1_svc(init_sec_context_args *argp,
init_sec_context_res *result, struct svc_req *rqstp)
{
gssd_verbose_out("gssd_init_sec_context: MIT\n");
result->major_status = GSS_S_UNAVAILABLE;
return (TRUE);
}
bool_t
gssd_accept_sec_context_1_svc(accept_sec_context_args *argp,
accept_sec_context_res *result, struct svc_req *rqstp)
{
gssd_verbose_out("gssd_accept_sec_context: MIT\n");
result->major_status = GSS_S_UNAVAILABLE;
return (TRUE);
}
bool_t
gssd_init_sec_context_lucid_v1_1_svc(init_sec_context_lucid_v1_args *argp,
init_sec_context_lucid_v1_res *result, struct svc_req *rqstp)
{
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
gss_name_t name = GSS_C_NO_NAME;
char ccname[PATH_MAX + 5 + 1], *cp, *cp2;
int gotone, gotcred;
OM_uint32 min_stat;
gss_buffer_desc principal_desc;
char enctype[sizeof(uint32_t)];
int key_enctype;
OM_uint32 maj_stat;
memset(result, 0, sizeof(*result));
if (hostbased_initiator_cred != 0 && argp->cred != 0 &&
argp->uid == 0) {
/*
* These credentials are for a host based initiator name
* in a keytab file, which should now have credentials
* in /tmp/krb5cc_gssd, because gss_acquire_cred() did
* the equivalent of "kinit -k".
*/
snprintf(ccname, sizeof(ccname), "FILE:%s",
GSSD_CREDENTIAL_CACHE_FILE);
} else if (ccfile_dirlist[0] != '\0' && argp->cred == 0) {
/*
* For the "-s" case and no credentials provided as an
* argument, search the directory list for an appropriate
* credential cache file. If the search fails, return failure.
*/
gotone = 0;
cp = ccfile_dirlist;
do {
cp2 = strchr(cp, ':');
if (cp2 != NULL)
*cp2 = '\0';
gotone = find_ccache_file(cp, argp->uid, ccname);
if (gotone != 0)
break;
if (cp2 != NULL)
*cp2++ = ':';
cp = cp2;
} while (cp != NULL && *cp != '\0');
if (gotone == 0) {
result->major_status = GSS_S_CREDENTIALS_EXPIRED;
gssd_verbose_out("gssd_init_sec_context_plus: -s no"
" credential cache file found for uid=%d\n",
(int)argp->uid);
return (TRUE);
}
} else {
/*
* If there wasn't a "-s" option or the credentials have
* been provided as an argument, do it the old way.
* When credentials are provided, the uid should be root.
*/
if (argp->cred != 0 && argp->uid != 0) {
if (debug_level == 0)
syslog(LOG_ERR, "gss_init_sec_context_plus:"
" cred for non-root");
else
fprintf(stderr, "gss_init_sec_context_plus:"
" cred for non-root\n");
}
snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d",
(int) argp->uid);
}
setenv("KRB5CCNAME", ccname, TRUE);
if (argp->cred) {
cred = gssd_find_resource(argp->cred);
if (!cred) {
result->major_status = GSS_S_CREDENTIALS_EXPIRED;
gssd_verbose_out("gssd_init_sec_context_plus: cred"
" resource not found\n");
return (TRUE);
}
}
if (argp->ctx) {
ctx = gssd_find_resource(argp->ctx);
if (!ctx) {
result->major_status = GSS_S_CONTEXT_EXPIRED;
gssd_verbose_out("gssd_init_sec_context_plus: context"
" resource not found\n");
return (TRUE);
}
}
if (argp->name) {
name = gssd_find_resource(argp->name);
if (!name) {
result->major_status = GSS_S_BAD_NAME;
gssd_verbose_out("gssd_init_sec_context_plus: name"
" resource not found\n");
return (TRUE);
}
}
gotcred = 0;
result->major_status = gss_init_sec_context(&result->minor_status,
cred, &ctx, name, argp->mech_type,
argp->req_flags, argp->time_req, argp->input_chan_bindings,
&argp->input_token, &result->actual_mech_type,
&result->output_token, &result->ret_flags, &result->time_rec);
gssd_verbose_out("gssd_init_sec_context_plus: done major=0x%x minor=%d"
" uid=%d\n", (unsigned int)result->major_status,
(int)result->minor_status, (int)argp->uid);
if (gotcred != 0)
gss_release_cred(&min_stat, &cred);
if (result->actual_mech_type) {
/*
* Just to keep the bogus "elements" pointer
* from core dumping the daemon when linked to MIT
* libraries. For some reason, the "elements" pointer
* in actual_mech_type cannot be read.
*/
result->actual_mech_type = GSS_KRB5_MECH_OID_X;
}
if (result->major_status == GSS_S_COMPLETE
|| result->major_status == GSS_S_CONTINUE_NEEDED) {
if (argp->ctx)
result->ctx = argp->ctx;
else
result->ctx = gssd_make_resource(ctx);
}
if (result->major_status == GSS_S_COMPLETE) {
gss_krb5_lucid_context_v1_t *lctx;
result->major_status = gss_krb5_export_lucid_sec_context(
&result->minor_status, &ctx, 1, (void *)&lctx);
gssd_delete_resource(result->ctx);
if (result->major_status == GSS_S_COMPLETE &&
lctx != NULL) {
result->lucid.initiate = lctx->initiate;
result->lucid.endtime = lctx->endtime;
result->lucid.send_seq = lctx->send_seq;
result->lucid.recv_seq = lctx->recv_seq;
result->lucid.protocol = lctx->protocol;
if (lctx->protocol == 0) {
result->lucid.rfc_sign =
lctx->rfc1964_kd.sign_alg;
result->lucid.rfc_seal =
lctx->rfc1964_kd.seal_alg;
result->lucid.ctx_type =
lctx->rfc1964_kd.ctx_key.type;
result->lucid.ctx_key.length =
lctx->rfc1964_kd.ctx_key.length;
result->lucid.ctx_key.value =
mem_alloc(result->lucid.ctx_key.length);
memcpy(result->lucid.ctx_key.value,
lctx->rfc1964_kd.ctx_key.data,
result->lucid.ctx_key.length);
} else if (lctx->protocol == 1) {
result->lucid.have_subkey =
lctx->cfx_kd.have_acceptor_subkey;
result->lucid.ctx_type =
lctx->cfx_kd.ctx_key.type;
result->lucid.ctx_key.length =
lctx->cfx_kd.ctx_key.length;
result->lucid.ctx_key.value =
mem_alloc(result->lucid.ctx_key.length);
memcpy(result->lucid.ctx_key.value,
lctx->cfx_kd.ctx_key.data,
result->lucid.ctx_key.length);
if (result->lucid.have_subkey != 0) {
result->lucid.subkey_type =
lctx->cfx_kd.acceptor_subkey.type;
result->lucid.subkey_key.length =
lctx->cfx_kd.acceptor_subkey.length;
result->lucid.subkey_key.value =
mem_alloc(
result->lucid.subkey_key.length);
memcpy(result->lucid.subkey_key.value,
lctx->cfx_kd.acceptor_subkey.data,
result->lucid.subkey_key.length);
} else {
result->lucid.subkey_type = 0;
result->lucid.subkey_key.length = 0;
result->lucid.subkey_key.value = NULL;
}
}
(void)gss_krb5_free_lucid_sec_context(&min_stat,
(void *)lctx);
} else {
gssd_verbose_out("gss_krb5_export_lucid_set_context"
" failed: major=0x%x minor=%d lctx=%p\n",
result->major_status, result->minor_status, lctx);
}
}
return (TRUE);
}
/*
* Internal function to acquire unix credentials.
*/
static OM_uint32
_gss_get_unix_cred(OM_uint32 *minor_stat, gss_name_t name, gss_OID mech,
uid_t *uidp, gid_t *gidp, int *numgroups, gid_t *groups)
{
OM_uint32 major_stat;
uid_t uid;
char buf[1024], *bufp;
struct passwd pwd, *pw;
size_t buflen;
int error;
static size_t buflen_hint = 1024;
major_stat = gss_pname_to_uid(minor_stat, name, mech, &uid);
if (major_stat == GSS_S_COMPLETE) {
*uidp = uid;
buflen = buflen_hint;
for (;;) {
pw = NULL;
bufp = buf;
if (buflen > sizeof(buf))
bufp = malloc(buflen);
if (bufp == NULL)
break;
error = getpwuid_r(uid, &pwd, bufp, buflen,
&pw);
if (error != ERANGE)
break;
if (buflen > sizeof(buf))
free(bufp);
buflen += 1024;
if (buflen > buflen_hint)
buflen_hint = buflen;
}
if (pw) {
*gidp = pw->pw_gid;
getgrouplist(pw->pw_name, pw->pw_gid,
groups, numgroups);
} else {
major_stat = GSS_S_FAILURE;
gssd_verbose_out("get_unix_cred: cannot find"
" passwd entry\n");
}
if (bufp != NULL && buflen > sizeof(buf))
free(bufp);
} else if (major_stat != GSS_S_UNAVAILABLE) {
gssd_verbose_out("gssd_pname_to_uid: failed major=0x%x"
" minor=%d\n", major_stat, *minor_stat);
}
return (major_stat);
}
bool_t
gssd_accept_sec_context_lucid_v1_1_svc(accept_sec_context_lucid_v1_args *argp,
accept_sec_context_lucid_v1_res *result, struct svc_req *rqstp)
{
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
gss_name_t src_name;
gss_cred_id_t delegated_cred_handle;
OM_uint32 min_stat;
memset(result, 0, sizeof(*result));
if (argp->ctx) {
ctx = gssd_find_resource(argp->ctx);
if (!ctx) {
result->major_status = GSS_S_CONTEXT_EXPIRED;
gssd_verbose_out("gssd_accept_sec_context: ctx"
" resource not found\n");
return (TRUE);
}
}
if (argp->cred) {
cred = gssd_find_resource(argp->cred);
if (!cred) {
result->major_status = GSS_S_CREDENTIALS_EXPIRED;
gssd_verbose_out("gssd_accept_sec_context: cred"
" resource not found\n");
return (TRUE);
}
}
memset(result, 0, sizeof(*result));
result->major_status = gss_accept_sec_context(&result->minor_status,
&ctx, cred, &argp->input_token, argp->input_chan_bindings,
&src_name, &result->mech_type, &result->output_token,
&result->ret_flags, &result->time_rec,
&delegated_cred_handle);
gssd_verbose_out("gssd_accept_sec_context: done major=0x%x minor=%d\n",
(unsigned int)result->major_status, (int)result->minor_status);
if (result->major_status == GSS_S_COMPLETE
|| result->major_status == GSS_S_CONTINUE_NEEDED) {
if (argp->ctx)
result->ctx = argp->ctx;
else
result->ctx = gssd_make_resource(ctx);
result->src_name = gssd_make_resource(src_name);
result->delegated_cred_handle =
gssd_make_resource(delegated_cred_handle);
}
if (result->major_status == GSS_S_COMPLETE) {
gss_krb5_lucid_context_v1_t *lctx;
/* Get the lucid context stuff. */
result->major_status = gss_krb5_export_lucid_sec_context(
&result->minor_status, &ctx, 1, (void *)&lctx);
gssd_delete_resource(result->ctx);
if (result->major_status == GSS_S_COMPLETE &&
lctx != NULL) {
result->lucid.initiate = lctx->initiate;
result->lucid.endtime = lctx->endtime;
result->lucid.send_seq = lctx->send_seq;
result->lucid.recv_seq = lctx->recv_seq;
result->lucid.protocol = lctx->protocol;
if (lctx->protocol == 0) {
result->lucid.rfc_sign =
lctx->rfc1964_kd.sign_alg;
result->lucid.rfc_seal =
lctx->rfc1964_kd.seal_alg;
result->lucid.ctx_type =
lctx->rfc1964_kd.ctx_key.type;
result->lucid.ctx_key.length =
lctx->rfc1964_kd.ctx_key.length;
result->lucid.ctx_key.value =
mem_alloc(result->lucid.ctx_key.length);
memcpy(result->lucid.ctx_key.value,
lctx->rfc1964_kd.ctx_key.data,
result->lucid.ctx_key.length);
} else if (lctx->protocol == 1) {
result->lucid.have_subkey =
lctx->cfx_kd.have_acceptor_subkey;
result->lucid.ctx_type =
lctx->cfx_kd.ctx_key.type;
result->lucid.ctx_key.length =
lctx->cfx_kd.ctx_key.length;
result->lucid.ctx_key.value =
mem_alloc(result->lucid.ctx_key.length);
memcpy(result->lucid.ctx_key.value,
lctx->cfx_kd.ctx_key.data,
result->lucid.ctx_key.length);
if (result->lucid.have_subkey != 0) {
result->lucid.subkey_type =
lctx->cfx_kd.acceptor_subkey.type;
result->lucid.subkey_key.length =
lctx->cfx_kd.acceptor_subkey.length;
result->lucid.subkey_key.value =
mem_alloc(
result->lucid.subkey_key.length);
memcpy(result->lucid.subkey_key.value,
lctx->cfx_kd.acceptor_subkey.data,
result->lucid.subkey_key.length);
} else {
result->lucid.subkey_type = 0;
result->lucid.subkey_key.length = 0;
result->lucid.subkey_key.value = NULL;
}
}
(void)gss_krb5_free_lucid_sec_context(&min_stat,
(void *)lctx);
} else {
gssd_verbose_out("gss_krb5_export_lucid_set_context"
" failed: major=0x%x minor=%d lctx=%p\n",
result->major_status, result->minor_status, lctx);
}
/* Now, get the exported name. */
if (result->major_status == GSS_S_COMPLETE) {
result->major_status = gss_export_name(
&result->minor_status, src_name,
&result->exported_name);
gssd_verbose_out("gssd_accept_sec_context (name):"
" done major=0x%x minor=%d\n",
result->major_status, result->minor_status);
}
/* Finally, get the unix credentials. */
if (result->major_status == GSS_S_COMPLETE) {
gid_t groups[NGROUPS];
int i, len = NGROUPS;
OM_uint32 major_stat, minor_stat;
major_stat = _gss_get_unix_cred(&minor_stat,
src_name, result->mech_type,
&result->uid, &result->gid, &len, groups);
if (major_stat == GSS_S_COMPLETE) {
result->gidlist.gidlist_len = len;
result->gidlist.gidlist_val =
mem_alloc(len * sizeof(uint32_t));
/*
* Just in case
* sizeof(gid_t) != sizeof(uint32_t).
*/
for (i = 0; i < len; i++)
result->gidlist.gidlist_val[i] =
groups[i];
} else {
result->gid = 65534;
result->gidlist.gidlist_len = 0;
result->gidlist.gidlist_val = NULL;
gssd_verbose_out("gssd_pname_to_uid: mapped"
" to uid=%d, but no groups\n",
(int)result->uid);
}
}
}
return (TRUE);
}
#endif /* !MK_MITKRB5 */
bool_t
gssd_delete_sec_context_1_svc(delete_sec_context_args *argp, delete_sec_context_res *result, struct svc_req *rqstp)
@ -761,11 +1213,9 @@ gssd_acquire_cred_1_svc(acquire_cred_args *argp, acquire_cred_res *result, struc
gss_cred_id_t cred;
char ccname[PATH_MAX + 5 + 1], *cp, *cp2;
int gotone;
#ifndef WITHOUT_KERBEROS
gss_buffer_desc namebuf;
uint32_t minstat;
krb5_error_code kret;
#endif
memset(result, 0, sizeof(*result));
if (argp->desired_name) {
@ -778,7 +1228,6 @@ gssd_acquire_cred_1_svc(acquire_cred_args *argp, acquire_cred_res *result, struc
}
}
#ifndef WITHOUT_KERBEROS
if (hostbased_initiator_cred != 0 && argp->desired_name != 0 &&
argp->uid == 0 && argp->cred_usage == GSS_C_INITIATE) {
/* This is a host based initiator name in the keytab file. */
@ -811,9 +1260,7 @@ gssd_acquire_cred_1_svc(acquire_cred_args *argp, acquire_cred_res *result, struc
result->major_status = GSS_S_FAILURE;
return (TRUE);
}
} else
#endif /* !WITHOUT_KERBEROS */
if (ccfile_dirlist[0] != '\0' && argp->desired_name == 0) {
} else if (ccfile_dirlist[0] != '\0' && argp->desired_name == 0) {
/*
* For the "-s" case and no name provided as an
* argument, search the directory list for an appropriate
@ -1057,7 +1504,6 @@ static int
is_a_valid_tgt_cache(const char *filepath, uid_t uid, int *retrating,
time_t *retexptime)
{
#ifndef WITHOUT_KERBEROS
krb5_context context;
krb5_principal princ;
krb5_ccache ccache;
@ -1157,12 +1603,8 @@ is_a_valid_tgt_cache(const char *filepath, uid_t uid, int *retrating,
*retexptime = exptime;
}
return (ret);
#else /* WITHOUT_KERBEROS */
return (0);
#endif /* !WITHOUT_KERBEROS */
}
#ifndef WITHOUT_KERBEROS
/*
* This function attempts to do essentially a "kinit -k" for the principal
* name provided as the argument, so that there will be a TGT in the
@ -1265,15 +1707,12 @@ gssd_get_user_cred(OM_uint32 *min_statp, uid_t uid, gss_cred_id_t *credp)
gss_release_oid_set(&min_stat, &mechlist);
return (maj_stat);
}
#endif /* !WITHOUT_KERBEROS */
void gssd_terminate(int sig __unused)
{
#ifndef WITHOUT_KERBEROS
if (hostbased_initiator_cred != 0)
unlink(GSSD_CREDENTIAL_CACHE_FILE);
#endif
exit(0);
}