#include <config.h>
#if defined(AUTH_GSS_NEGOTIATE) && AUTH_GSS_NEGOTIATE
#include <gssauth.h>
#include <gssauthcn.h>
#define RPC__GSSAUTH_CN_AUTH_PADDING 16
INTERNAL boolean32 rpc__gssauth_cn_three_way_winnt (void);
INTERNAL boolean32 rpc__gssauth_cn_three_way_gss (void);
INTERNAL boolean32 rpc__gssauth_cn_context_valid (
rpc_cn_sec_context_p_t ,
unsigned32 *
);
INTERNAL void rpc__gssauth_negotiate_cn_create_info (
rpc_authn_level_t ,
rpc_auth_info_p_t * ,
unsigned32 *
);
INTERNAL void rpc__gssauth_mskrb_cn_create_info (
rpc_authn_level_t ,
rpc_auth_info_p_t * ,
unsigned32 *
);
INTERNAL void rpc__gssauth_winnt_cn_create_info (
rpc_authn_level_t ,
rpc_auth_info_p_t * ,
unsigned32 *
);
INTERNAL void rpc__gssauth_netlogon_cn_create_info (
rpc_authn_level_t ,
rpc_auth_info_p_t * ,
unsigned32 *
);
INTERNAL boolean32 rpc__gssauth_cn_cred_changed (
rpc_cn_sec_context_p_t ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_cred_refresh (
rpc_auth_info_p_t ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_fmt_client_req (
rpc_cn_assoc_sec_context_p_t ,
rpc_cn_sec_context_p_t ,
dce_pointer_t ,
unsigned32 * ,
dce_pointer_t * ,
unsigned32 * ,
unsigned32 ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_fmt_srvr_resp (
unsigned32 ,
rpc_cn_assoc_sec_context_p_t ,
rpc_cn_sec_context_p_t ,
dce_pointer_t ,
unsigned32 ,
dce_pointer_t ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_free_prot_info (
rpc_auth_info_p_t ,
rpc_cn_auth_info_p_t *
);
INTERNAL void rpc__gssauth_cn_get_prot_info (
rpc_auth_info_p_t ,
rpc_cn_auth_info_p_t * ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_pre_call (
rpc_cn_assoc_sec_context_p_t ,
rpc_cn_sec_context_p_t ,
dce_pointer_t ,
unsigned32 * ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_pre_send (
rpc_cn_assoc_sec_context_p_t ,
rpc_cn_sec_context_p_t ,
rpc_socket_iovec_p_t ,
unsigned32 ,
rpc_socket_iovec_p_t ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_recv_check (
rpc_cn_assoc_sec_context_p_t ,
rpc_cn_sec_context_p_t ,
rpc_cn_common_hdr_p_t ,
unsigned32 ,
unsigned32 ,
rpc_cn_auth_tlr_p_t ,
boolean32 ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_tlr_uuid_crc (
dce_pointer_t ,
unsigned32 ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_tlr_unpack (
rpc_cn_packet_p_t ,
unsigned32 ,
unsigned8 *
);
INTERNAL void rpc__gssauth_cn_vfy_client_req (
rpc_cn_assoc_sec_context_p_t ,
rpc_cn_sec_context_p_t ,
dce_pointer_t ,
unsigned32 ,
unsigned32 ,
unsigned32 *
);
INTERNAL void rpc__gssauth_cn_vfy_srvr_resp (
rpc_cn_assoc_sec_context_p_t ,
rpc_cn_sec_context_p_t ,
dce_pointer_t ,
unsigned32 ,
unsigned32 *
);
INTERNAL const rpc_cn_auth_epv_t rpc_g_gssauth_negotiate_cn_epv =
{
.three_way = rpc__gssauth_cn_three_way_gss,
.context_valid = rpc__gssauth_cn_context_valid,
.create_info = rpc__gssauth_negotiate_cn_create_info,
.cred_changed = rpc__gssauth_cn_cred_changed,
.cred_refresh = rpc__gssauth_cn_cred_refresh,
.fmt_client_req = rpc__gssauth_cn_fmt_client_req,
.fmt_srvr_resp = rpc__gssauth_cn_fmt_srvr_resp,
.free_prot_info = rpc__gssauth_cn_free_prot_info,
.get_prot_info = rpc__gssauth_cn_get_prot_info,
.pre_call = rpc__gssauth_cn_pre_call,
.pre_send = rpc__gssauth_cn_pre_send,
.recv_check = rpc__gssauth_cn_recv_check,
.tlr_uuid_crc = rpc__gssauth_cn_tlr_uuid_crc,
.tlr_unpack = rpc__gssauth_cn_tlr_unpack,
.vfy_client_req = rpc__gssauth_cn_vfy_client_req,
.vfy_srvr_resp = rpc__gssauth_cn_vfy_srvr_resp
};
INTERNAL const rpc_cn_auth_epv_t rpc_g_gssauth_mskrb_cn_epv =
{
.three_way = rpc__gssauth_cn_three_way_gss,
.context_valid = rpc__gssauth_cn_context_valid,
.create_info = rpc__gssauth_mskrb_cn_create_info,
.cred_changed = rpc__gssauth_cn_cred_changed,
.cred_refresh = rpc__gssauth_cn_cred_refresh,
.fmt_client_req = rpc__gssauth_cn_fmt_client_req,
.fmt_srvr_resp = rpc__gssauth_cn_fmt_srvr_resp,
.free_prot_info = rpc__gssauth_cn_free_prot_info,
.get_prot_info = rpc__gssauth_cn_get_prot_info,
.pre_call = rpc__gssauth_cn_pre_call,
.pre_send = rpc__gssauth_cn_pre_send,
.recv_check = rpc__gssauth_cn_recv_check,
.tlr_uuid_crc = rpc__gssauth_cn_tlr_uuid_crc,
.tlr_unpack = rpc__gssauth_cn_tlr_unpack,
.vfy_client_req = rpc__gssauth_cn_vfy_client_req,
.vfy_srvr_resp = rpc__gssauth_cn_vfy_srvr_resp
};
INTERNAL const rpc_cn_auth_epv_t rpc_g_gssauth_winnt_cn_epv =
{
.three_way = rpc__gssauth_cn_three_way_winnt,
.context_valid = rpc__gssauth_cn_context_valid,
.create_info = rpc__gssauth_winnt_cn_create_info,
.cred_changed = rpc__gssauth_cn_cred_changed,
.cred_refresh = rpc__gssauth_cn_cred_refresh,
.fmt_client_req = rpc__gssauth_cn_fmt_client_req,
.fmt_srvr_resp = rpc__gssauth_cn_fmt_srvr_resp,
.free_prot_info = rpc__gssauth_cn_free_prot_info,
.get_prot_info = rpc__gssauth_cn_get_prot_info,
.pre_call = rpc__gssauth_cn_pre_call,
.pre_send = rpc__gssauth_cn_pre_send,
.recv_check = rpc__gssauth_cn_recv_check,
.tlr_uuid_crc = rpc__gssauth_cn_tlr_uuid_crc,
.tlr_unpack = rpc__gssauth_cn_tlr_unpack,
.vfy_client_req = rpc__gssauth_cn_vfy_client_req,
.vfy_srvr_resp = rpc__gssauth_cn_vfy_srvr_resp
};
INTERNAL const rpc_cn_auth_epv_t rpc_g_gssauth_netlogon_cn_epv =
{
.three_way = rpc__gssauth_cn_three_way_gss,
.context_valid = rpc__gssauth_cn_context_valid,
.create_info = rpc__gssauth_netlogon_cn_create_info,
.cred_changed = rpc__gssauth_cn_cred_changed,
.cred_refresh = rpc__gssauth_cn_cred_refresh,
.fmt_client_req = rpc__gssauth_cn_fmt_client_req,
.fmt_srvr_resp = rpc__gssauth_cn_fmt_srvr_resp,
.free_prot_info = rpc__gssauth_cn_free_prot_info,
.get_prot_info = rpc__gssauth_cn_get_prot_info,
.pre_call = rpc__gssauth_cn_pre_call,
.pre_send = rpc__gssauth_cn_pre_send,
.recv_check = rpc__gssauth_cn_recv_check,
.tlr_uuid_crc = rpc__gssauth_cn_tlr_uuid_crc,
.tlr_unpack = rpc__gssauth_cn_tlr_unpack,
.vfy_client_req = rpc__gssauth_cn_vfy_client_req,
.vfy_srvr_resp = rpc__gssauth_cn_vfy_srvr_resp
};
INTERNAL boolean32 rpc__gssauth_cn_three_way_winnt (void)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_three_way)\n"));
return true;
}
INTERNAL boolean32 rpc__gssauth_cn_three_way_gss (void)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_three_way)\n"));
return false;
}
INTERNAL boolean32 rpc__gssauth_cn_context_valid
(
rpc_cn_sec_context_p_t sec,
unsigned32 *st
)
{
CODING_ERROR (st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_context_valid)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_context_valid) prot->%x level->%x key_id->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_CONTEXT_VALID)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return false;
}
#endif
*st = rpc_s_ok;
return true;
}
INTERNAL void rpc__gssauth_cn_create_info
(
rpc_authn_protocol_id_t authn_protocol,
rpc_authn_level_t authn_level,
rpc_auth_info_p_t *auth_info,
unsigned32 *st
)
{
rpc_gssauth_info_p_t gssauth_info;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_create_info)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_create_info) prot->%x level->%x\n",
authn_protocol,
authn_level));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_CREATE_INFO)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
switch (authn_level) {
case rpc_c_authn_level_connect:
case rpc_c_authn_level_pkt_integrity:
case rpc_c_authn_level_pkt_privacy:
break;
default:
*st = rpc_s_unsupported_authn_level;
return;
}
RPC_MEM_ALLOC(gssauth_info,
rpc_gssauth_info_p_t,
sizeof (rpc_gssauth_info_t),
RPC_C_MEM_GSSAUTH_INFO,
RPC_C_MEM_WAITOK);
memset (gssauth_info, 0, sizeof(rpc_gssauth_info_t));
gssauth_info->auth_info.refcount = 1;
gssauth_info->auth_info.server_princ_name = '\0';
gssauth_info->auth_info.authn_level = authn_level;
gssauth_info->auth_info.authn_protocol = authn_protocol;
gssauth_info->auth_info.authz_protocol = rpc_c_authz_name;
gssauth_info->auth_info.is_server = true;
*auth_info = &gssauth_info->auth_info;
*st = rpc_s_ok;
}
INTERNAL void rpc__gssauth_negotiate_cn_create_info
(
rpc_authn_level_t authn_level,
rpc_auth_info_p_t *auth_info,
unsigned32 *st
)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_negotiate_cn_create_info)\n"));
rpc__gssauth_cn_create_info(rpc_c_authn_gss_negotiate,
authn_level,
auth_info,
st);
}
INTERNAL void rpc__gssauth_mskrb_cn_create_info
(
rpc_authn_level_t authn_level,
rpc_auth_info_p_t *auth_info,
unsigned32 *st
)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_mskrb_cn_create_info)\n"));
rpc__gssauth_cn_create_info(rpc_c_authn_gss_mskrb,
authn_level,
auth_info,
st);
}
INTERNAL void rpc__gssauth_winnt_cn_create_info
(
rpc_authn_level_t authn_level,
rpc_auth_info_p_t *auth_info,
unsigned32 *st
)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_winnt_cn_create_info)\n"));
rpc__gssauth_cn_create_info(rpc_c_authn_winnt,
authn_level,
auth_info,
st);
}
INTERNAL void rpc__gssauth_netlogon_cn_create_info
(
rpc_authn_level_t authn_level,
rpc_auth_info_p_t *auth_info,
unsigned32 *st
)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_netlogon_cn_create_info)\n"));
rpc__gssauth_cn_create_info(rpc_c_authn_netlogon,
authn_level,
auth_info,
st);
}
INTERNAL boolean32 rpc__gssauth_cn_cred_changed
(
rpc_cn_sec_context_p_t sec,
unsigned32 *st
)
{
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_cred_changed)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_cred_changed) prot->%x level->%x key_id->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_CRED_CHANGED)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return false;
}
#endif
*st = rpc_s_ok;
return false;
}
INTERNAL void rpc__gssauth_cn_cred_refresh
(
rpc_auth_info_p_t auth_info,
unsigned32 *st
)
{
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_cred_refresh)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_cred_refresh) prot->%x level->%x\n",
auth_info->authn_protocol,
auth_info->authn_level));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_CRED_REFRESH)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
*st = rpc_s_ok;
}
PRIVATE const char *rpc__gssauth_error_map
(
OM_uint32 maj_stat,
OM_uint32 min_stat,
const gss_OID mech,
char *message_buffer,
unsigned32 message_length,
unsigned32 *st
)
{
switch (maj_stat) {
case GSS_S_BAD_MECH:
*st = rpc_s_unknown_authn_service;
break;
case GSS_S_BAD_NAME:
*st = rpc_s_unsupported_name_syntax;
break;
case GSS_S_BAD_BINDINGS:
*st = rpc_s_auth_badaddr;
break;
case GSS_S_BAD_STATUS:
*st = rpc_s_unknown_status_code;
break;
case GSS_S_BAD_SIG:
*st = rpc_s_auth_bad_integrity;
break;
case GSS_S_NO_CRED:
case GSS_S_NO_CONTEXT:
*st = rpc_s_auth_nokey;
break;
case GSS_S_DEFECTIVE_TOKEN:
*st = rpc_s_auth_field_toolong;
break;
case GSS_S_DEFECTIVE_CREDENTIAL:
*st = rpc_s_invalid_credentials;
break;
case GSS_S_CONTEXT_EXPIRED:
*st = rpc_s_auth_tkt_expired;
break;
case GSS_S_BAD_QOP:
*st = rpc_s_protect_level_mismatch;
break;
case GSS_S_UNAUTHORIZED:
*st = rpc_s_authn_authz_mismatch;
break;
case GSS_S_NAME_NOT_MN:
*st = rpc_s_auth_not_us;
break;
case GSS_S_OLD_TOKEN:
case GSS_S_DUPLICATE_TOKEN:
*st = rpc_s_auth_repeat;
break;
case GSS_S_GAP_TOKEN:
*st = rpc_s_auth_badorder;
break;
case GSS_S_UNSEQ_TOKEN:
*st = rpc_s_auth_badseq;
break;
case GSS_S_CONTINUE_NEEDED:
*st = rpc_s_partial_credentials;
break;
case GSS_S_COMPLETE:
*st = rpc_s_ok;
break;
case GSS_S_DUPLICATE_ELEMENT:
case GSS_S_UNAVAILABLE:
case GSS_S_FAILURE:
default:
*st = rpc_s_auth_method;
break;
}
switch ((signed32) min_stat) {
case KRB5KRB_AP_ERR_BAD_INTEGRITY:
*st = rpc_s_auth_bad_integrity;
break;
case KRB5KRB_AP_ERR_TKT_EXPIRED:
*st = rpc_s_auth_tkt_expired;
break;
case KRB5KRB_AP_ERR_TKT_NYV:
*st = rpc_s_auth_tkt_nyv;
break;
case KRB5KRB_AP_ERR_REPEAT:
*st = rpc_s_auth_repeat;
break;
case KRB5KRB_AP_ERR_NOT_US:
*st = rpc_s_auth_not_us;
break;
case KRB5KRB_AP_ERR_BADMATCH:
*st = rpc_s_auth_badmatch;
break;
case KRB5KRB_AP_ERR_SKEW:
*st = rpc_s_auth_skew;
break;
case KRB5KRB_AP_ERR_BADADDR:
*st = rpc_s_auth_badaddr;
break;
case KRB5KRB_AP_ERR_BADVERSION:
*st = rpc_s_auth_badversion;
break;
case KRB5KRB_AP_ERR_MSG_TYPE:
*st = rpc_s_auth_msg_type;
break;
case KRB5KRB_AP_ERR_MODIFIED:
*st = rpc_s_auth_modified;
break;
case KRB5KRB_AP_ERR_BADORDER:
*st = rpc_s_auth_badorder;
break;
case KRB5KRB_AP_ERR_BADKEYVER:
*st = rpc_s_auth_badkeyver;
break;
case KRB5KRB_AP_ERR_NOKEY:
*st = rpc_s_auth_nokey;
break;
case KRB5KRB_AP_ERR_MUT_FAIL:
*st = rpc_s_auth_mut_fail;
break;
case KRB5KRB_AP_ERR_BADDIRECTION:
*st = rpc_s_auth_baddirection;
break;
case KRB5KRB_AP_ERR_METHOD:
*st = rpc_s_auth_method;
break;
case KRB5KRB_AP_ERR_BADSEQ:
*st = rpc_s_auth_badseq;
break;
case KRB5KRB_AP_ERR_INAPP_CKSUM:
*st = rpc_s_auth_inapp_cksum;
break;
default:
break;
}
if (message_buffer != NULL && message_length != 0) {
OM_uint32 min2;
gss_buffer_desc major_msg;
gss_buffer_desc minor_msg;
OM_uint32 msg_ctx = 0;
major_msg.value = NULL;
major_msg.length = 0;
minor_msg.value = NULL;
minor_msg.length = 0;
gss_display_status(&min2, maj_stat, GSS_C_GSS_CODE,
NULL, &msg_ctx, &major_msg);
gss_display_status(&min2, min_stat, GSS_C_MECH_CODE,
mech, &msg_ctx, &minor_msg);
snprintf((char *)message_buffer, message_length - 1,
"major: %*s (%u) minor: %*s (%u) => dcerpc: (0x%08x)\n",
(int)major_msg.length, (char *)major_msg.value,
maj_stat, (int)minor_msg.length,
(char *)minor_msg.value, min_stat,
(unsigned int)*st);
message_buffer[message_length - 1] = '\0';
gss_release_buffer(&min2, &major_msg);
gss_release_buffer(&min2, &minor_msg);
return (const char *)message_buffer;
}
return NULL;
}
INTERNAL OM_uint32 rpc__gssauth_select_flags
(
OM_uint32 *min_stat,
rpc_authn_level_t authn_level,
OM_uint32 *req_flags
)
{
OM_uint32 flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE;
*min_stat = 0;
switch (authn_level) {
case rpc_c_authn_level_connect:
break;
case rpc_c_protect_level_pkt_integ:
flags |= GSS_C_INTEG_FLAG;
break;
case rpc_c_protect_level_pkt_privacy:
flags |= GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
break;
}
*req_flags = flags;
return GSS_S_COMPLETE;
}
INTERNAL OM_uint32 rpc__gssauth_create_client_token
(
OM_uint32 *min_stat,
const rpc_cn_sec_context_p_t sec,
const gss_cred_id_t gss_creds,
const gss_name_t gss_server_name,
gss_ctx_id_t *gss_ctx,
gss_OID *actual_mech,
gss_buffer_desc *output_token
)
{
OM_uint32 maj_stat;
gss_OID req_mech = GSS_C_NO_OID;
OM_uint32 req_flags;
gss_buffer_desc input_token;
maj_stat = rpc__gssauth_select_mech(min_stat,
sec->sec_info->authn_protocol,
&req_mech);
if (maj_stat != GSS_S_COMPLETE) {
return maj_stat;
}
maj_stat = rpc__gssauth_select_flags(min_stat,
sec->sec_info->authn_level,
&req_flags);
if (maj_stat != GSS_S_COMPLETE) {
return maj_stat;
}
input_token.value = NULL;
input_token.length = 0;
maj_stat = gss_init_sec_context(min_stat,
gss_creds,
gss_ctx,
gss_server_name,
req_mech,
req_flags,
GSS_C_INDEFINITE,
NULL,
&input_token,
actual_mech,
output_token,
NULL,
NULL);
return maj_stat;
}
INTERNAL OM_uint32 rpc__gssauth_verify_server_token
(
OM_uint32 *min_stat,
const rpc_cn_sec_context_p_t sec,
const gss_cred_id_t gss_creds,
const gss_name_t gss_server_name,
gss_ctx_id_t gss_ctx,
gss_buffer_desc input_token,
gss_OID *actual_mech,
gss_buffer_desc *output_token
)
{
OM_uint32 maj_stat;
gss_OID req_mech = GSS_C_NO_OID;
OM_uint32 req_flags;
assert(gss_ctx != GSS_C_NO_CONTEXT);
maj_stat = rpc__gssauth_select_mech(min_stat,
sec->sec_info->authn_protocol,
&req_mech);
if (maj_stat != GSS_S_COMPLETE) {
return maj_stat;
}
maj_stat = rpc__gssauth_select_flags(min_stat,
sec->sec_info->authn_protocol,
&req_flags);
if (maj_stat != GSS_S_COMPLETE) {
return maj_stat;
}
maj_stat = gss_init_sec_context(min_stat,
gss_creds,
&gss_ctx,
gss_server_name,
req_mech,
req_flags,
GSS_C_INDEFINITE,
NULL,
&input_token,
actual_mech,
output_token,
NULL,
NULL);
return maj_stat;
}
INTERNAL void rpc__gssauth_cn_fmt_client_req
(
rpc_cn_assoc_sec_context_p_t assoc_sec ATTRIBUTE_UNUSED,
rpc_cn_sec_context_p_t sec,
dce_pointer_t auth_value,
unsigned32 *auth_value_len,
dce_pointer_t *last_auth_pos ATTRIBUTE_UNUSED,
unsigned32 *auth_len_remain,
unsigned32 old_server ATTRIBUTE_UNUSED,
unsigned32 *st
)
{
rpc_gssauth_info_p_t gssauth_info = (rpc_gssauth_info_p_t)sec->sec_info;
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
int maj_stat;
OM_uint32 min_stat;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_fmt_client_req)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_fmt_client_req) prot->%x level->%x key_id->%x assoc_uuid_crc->%x xmit_seq->%x recv_seq->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id,
assoc_sec->assoc_uuid_crc,
assoc_sec->assoc_next_snd_seq,
assoc_sec->assoc_next_rcv_seq));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_FMT_CLIENT_REQ)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
if (gssauth_cn_info->gss_ctx != GSS_C_NO_CONTEXT) {
output_token.length = assoc_sec->krb_message.length;
output_token.value = assoc_sec->krb_message.data;
assoc_sec->krb_message.length = 0;
assoc_sec->krb_message.data = NULL;
} else {
maj_stat = rpc__gssauth_create_client_token(&min_stat,
sec,
gssauth_info->gss_creds,
gssauth_info->gss_server_name,
&gssauth_cn_info->gss_ctx,
&gssauth_cn_info->gss_mech,
&output_token);
if (GSS_ERROR(maj_stat)) {
char msg[BUFSIZ];
rpc__gssauth_error_map(maj_stat, min_stat,
gssauth_cn_info->gss_mech,
msg, sizeof(msg), st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_fmt_client_req): %s\n", msg));
return;
}
gssauth_cn_info->gss_stat = maj_stat;
}
if (*auth_value_len < output_token.length) {
assoc_sec->krb_message.length = (int) output_token.length;
assoc_sec->krb_message.data = output_token.value;
*auth_value_len = (unsigned32) output_token.length;
memset((unsigned_char_p_t)auth_value, 0xAF, *auth_value_len);
} else {
*auth_value_len = (unsigned32) output_token.length;
*auth_len_remain = 0;
memcpy((unsigned_char_p_t)auth_value,
output_token.value,
output_token.length);
gss_release_buffer(&min_stat, &output_token);
}
*st = rpc_s_ok;
}
INTERNAL void rpc__gssauth_cn_fmt_srvr_resp
(
unsigned32 verify_st,
rpc_cn_assoc_sec_context_p_t assoc_sec,
rpc_cn_sec_context_p_t sec,
dce_pointer_t req_auth_value ATTRIBUTE_UNUSED ,
unsigned32 req_auth_value_len ATTRIBUTE_UNUSED ,
dce_pointer_t auth_value,
unsigned32 *auth_value_len
)
{
OM_uint32 min_stat;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_fmt_srvr_resp)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_fmt_srvr_resp) prot->%x level->%x key_id->%x assoc_uuid_crc->%x xmit_seq->%x recv_seq->%x, vfy_client_st->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id,
assoc_sec->assoc_uuid_crc,
assoc_sec->assoc_next_snd_seq,
assoc_sec->assoc_next_rcv_seq,
verify_st));
#if 0
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_FMT_SERVER_RESP)) {
verify_st = RPC_S_CN_DBG_AUTH_FAILURE;
}
#endif
output_token.length = assoc_sec->krb_message.length;
output_token.value = assoc_sec->krb_message.data;
assoc_sec->krb_message.length = 0;
assoc_sec->krb_message.data = NULL;
if (*auth_value_len < output_token.length) {
gss_release_buffer(&min_stat, &output_token);
*auth_value_len = 0;
return;
}
*auth_value_len = (unsigned32) output_token.length;
memcpy((unsigned_char_p_t)auth_value,
output_token.value,
output_token.length);
gss_release_buffer(&min_stat, &output_token);
}
INTERNAL void rpc__gssauth_cn_free_prot_info
(
rpc_auth_info_p_t info,
rpc_cn_auth_info_p_t *cn_info
)
{
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)*cn_info;
OM_uint32 min_stat;
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_free_prot_info)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_free_prot_info) prot->%x level->%x \n",
info->authn_protocol,
info->authn_level));
if (gssauth_cn_info->gss_ctx != GSS_C_NO_CONTEXT) {
gss_delete_sec_context(&min_stat,
&gssauth_cn_info->gss_ctx,
GSS_C_NO_BUFFER);
gssauth_cn_info->gss_ctx = GSS_C_NO_CONTEXT;
}
#if 0
if (gssauth_cn_info->gss_mech != GSS_C_NO_OID) {
gss_release_oid(&min_stat, &gssauth_cn_info->gss_mech);
gssauth_cn_info->gss_mech = GSS_C_NO_OID;
}
#endif
#ifdef DEBUG
memset (gssauth_cn_info, 0, sizeof (rpc_gssauth_cn_info_p_t));
#endif
RPC_MEM_FREE (gssauth_cn_info, RPC_C_MEM_GSSAUTH_CN_INFO);
*cn_info = NULL;
}
INTERNAL void rpc__gssauth_cn_get_prot_info
(
rpc_auth_info_p_t info,
rpc_cn_auth_info_p_t *cn_info,
unsigned32 *st
)
{
rpc_gssauth_cn_info_t *gssauth_cn_info = NULL;
rpc_gssauth_info_t *gssauth_info = (rpc_gssauth_info_p_t)info;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_get_prot_info)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_get_prot_info) prot->%x level->%x \n",
info->authn_protocol,
info->authn_level));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_GET_PROT_INFO)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
RPC_MEM_ALLOC(gssauth_cn_info,
rpc_gssauth_cn_info_p_t,
sizeof (rpc_gssauth_cn_info_t),
RPC_C_MEM_GSSAUTH_CN_INFO,
RPC_C_MEM_WAITOK);
memset (gssauth_cn_info, 0, sizeof(rpc_gssauth_cn_info_t));
if (info->is_server) {
gssauth_info->cn_info = gssauth_cn_info;
}
*cn_info = &gssauth_cn_info->cn_info;
*st = rpc_s_ok;
}
INTERNAL void rpc__gssauth_cn_pre_call
(
rpc_cn_assoc_sec_context_p_t assoc_sec,
rpc_cn_sec_context_p_t sec,
dce_pointer_t auth_value,
unsigned32 *auth_value_len,
unsigned32 *st
)
{
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
OM_uint32 maj_stat;
OM_uint32 min_stat;
gss_iov_buffer_desc iov[2];
int conf_req_flag = 0;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_pre_call)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_pre_call) prot->%x level->%x key_id->%x assoc_uuid_crc->%x xmit_seq->%x recv_seq->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id,
assoc_sec->assoc_uuid_crc,
assoc_sec->assoc_next_snd_seq,
assoc_sec->assoc_next_rcv_seq));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_PRE_CALL)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
if (gssauth_cn_info->gss_stat != GSS_S_COMPLETE) {
*st = rpc_s_ok;
return;
}
switch (sec->sec_info->authn_level) {
case rpc_c_protect_level_pkt_privacy:
conf_req_flag = 1;
case rpc_c_protect_level_pkt_integ:
iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
iov[0].buffer.length = RPC__GSSAUTH_CN_AUTH_PADDING;
iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
iov[1].buffer.length = 0;
maj_stat = gss_wrap_iov_length(&min_stat,
gssauth_cn_info->gss_ctx,
conf_req_flag,
GSS_C_QOP_DEFAULT,
NULL,
iov,
sizeof(iov)/sizeof(iov[0]));
if (maj_stat != GSS_S_COMPLETE) {
*st = rpc_s_auth_method;
return;
}
*auth_value_len = (unsigned32) iov[1].buffer.length;
memset((unsigned_char_p_t)auth_value, 0xAF, *auth_value_len);
break;
case rpc_c_authn_level_connect:
default:
*auth_value_len = 0;
break;
}
*st = rpc_s_ok;
}
INTERNAL void rpc__gssauth_cn_wrap_packet
(
rpc_cn_sec_context_p_t sec,
const char *comment,
unsigned8 header_size,
rpc_socket_iovec_p_t iov,
unsigned32 iovlen,
boolean conf_req_flag,
rpc_socket_iovec_p_t out_iov,
unsigned32 *st
)
{
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
rpc_cn_common_hdr_p_t pdu;
rpc_cn_auth_tlr_p_t auth_tlr;
unsigned32 i;
unsigned8 pad_len;
OM_uint32 maj_stat;
OM_uint32 min_stat;
int conf_state;
gss_iov_buffer_desc gss_iov[4];
unsigned_char_p_t pdu_buf;
size_t pdu_buflen, payload_len;
boolean header_sign = gssauth_cn_info->header_sign;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_wrap_packet)\n"));
if (iovlen < 2) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_wrap_packet): %s: iovlen[%u]\n",
comment, (unsigned int)iovlen));
*st = rpc_m_no_stub_data;
return;
}
if (iov[0].iov_len < header_size) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_wrap_packet): %s: iov[0].iov_len[%u] < header_size[%u]\n",
comment, (unsigned int)iov[0].iov_len,(unsigned int)header_size));
*st = rpc_m_no_stub_data;
return;
}
if (iov[iovlen - 1].iov_len < RPC_CN_PKT_SIZEOF_COM_AUTH_TLR) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_wrap_packet): %s: iov[%u].iov_len[%u] != %u\n",
comment,(unsigned int)iovlen - 1,
(unsigned int)iov[iovlen - 1].iov_len,
RPC_CN_PKT_SIZEOF_COM_AUTH_TLR));
*st = rpc_s_auth_field_toolong;
return;
}
for (i = 0, payload_len = 0; i < iovlen - 1; i++) {
payload_len += iov[i].iov_len;
}
payload_len -= header_size;
pad_len = RPC__GSSAUTH_CN_AUTH_PADDING -
(payload_len % RPC__GSSAUTH_CN_AUTH_PADDING);
if (pad_len == RPC__GSSAUTH_CN_AUTH_PADDING)
pad_len = 0;
pdu_buflen = header_size + payload_len + pad_len + iov[iovlen - 1].iov_len;
RPC_MEM_ALLOC(pdu_buf,
unsigned_char_p_t,
pdu_buflen,
RPC_C_MEM_CN_ENCRYPT_BUF,
RPC_C_MEM_WAITOK);
memset(pdu_buf, 0xAF, pdu_buflen);
pdu = (rpc_cn_common_hdr_p_t)pdu_buf;
for (i = 0, pdu_buflen = 0; i < iovlen - 1; i++) {
memcpy(&pdu_buf[pdu_buflen],
iov[i].iov_base,
iov[i].iov_len);
pdu_buflen += iov[i].iov_len;
}
memset(&pdu_buf[pdu_buflen], 0, pad_len);
gss_iov[0].type = header_sign ? GSS_IOV_BUFFER_TYPE_SIGN_ONLY :
GSS_IOV_BUFFER_TYPE_EMPTY;
gss_iov[0].buffer.value = pdu_buf;
gss_iov[0].buffer.length = header_size;
gss_iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
gss_iov[1].buffer.value = (unsigned_char_p_t)gss_iov[0].buffer.value +
gss_iov[0].buffer.length;
gss_iov[1].buffer.length = payload_len + pad_len;
gss_iov[2].type = header_sign ? GSS_IOV_BUFFER_TYPE_SIGN_ONLY :
GSS_IOV_BUFFER_TYPE_EMPTY;
gss_iov[2].buffer.value = (unsigned_char_p_t)gss_iov[1].buffer.value +
gss_iov[1].buffer.length;
gss_iov[2].buffer.length = RPC_CN_PKT_SIZEOF_COM_AUTH_TLR;
memcpy(gss_iov[2].buffer.value, iov[iovlen - 1].iov_base, gss_iov[2].buffer.length);
auth_tlr = (rpc_cn_auth_tlr_p_t)gss_iov[2].buffer.value;
auth_tlr->stub_pad_length = pad_len;
gss_iov[3].type = GSS_IOV_BUFFER_TYPE_HEADER;
gss_iov[3].buffer.value = (unsigned_char_p_t)gss_iov[2].buffer.value +
gss_iov[2].buffer.length;
gss_iov[3].buffer.length = iov[iovlen - 1].iov_len - RPC_CN_PKT_SIZEOF_COM_AUTH_TLR;
pdu->frag_len = gss_iov[0].buffer.length +
gss_iov[1].buffer.length +
gss_iov[2].buffer.length +
gss_iov[3].buffer.length;
pdu->auth_len = gss_iov[3].buffer.length;
if (conf_req_flag) {
maj_stat = gss_wrap_iov(&min_stat,
gssauth_cn_info->gss_ctx,
conf_req_flag,
GSS_C_QOP_DEFAULT,
&conf_state,
gss_iov,
sizeof(gss_iov)/sizeof(gss_iov[0]));
if (maj_stat != GSS_S_COMPLETE)
goto cleanup;
} else {
gss_buffer_desc input_token;
gss_buffer_desc mic_token;
conf_state = 0;
if (header_sign) {
input_token = gss_iov[0].buffer;
input_token.length += gss_iov[1].buffer.length + gss_iov[2].buffer.length;
} else {
input_token = gss_iov[1].buffer;
}
maj_stat = gss_get_mic(&min_stat,
gssauth_cn_info->gss_ctx,
GSS_C_QOP_DEFAULT,
&input_token,
&mic_token);
if (maj_stat != GSS_S_COMPLETE)
goto cleanup;
assert(mic_token.length <= gss_iov[3].buffer.length);
memcpy(gss_iov[3].buffer.value, mic_token.value, mic_token.length);
gss_iov[3].buffer.length = mic_token.length;
gss_release_buffer(&min_stat, &mic_token);
}
if (conf_req_flag != conf_state) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_wrap_packet): %s: conf_req[%u] != conf_state[%u]\n",
comment, (unsigned int)conf_req_flag, (unsigned int)conf_state));
*st = rpc_s_auth_method;
goto cleanup;
}
out_iov->iov_base = pdu_buf;
out_iov->iov_len = pdu->frag_len;
*st = rpc_s_ok;
cleanup:
if (maj_stat != GSS_S_COMPLETE) {
char msg[BUFSIZ];
rpc__gssauth_error_map(maj_stat, min_stat,
gssauth_cn_info->gss_mech,
msg, sizeof(msg), st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_wrap_packet): %s: %s\n", comment, msg));
}
return;
}
INTERNAL void rpc__gssauth_cn_create_large_frag
(
rpc_cn_assoc_sec_context_p_t assoc_sec,
const char *comment,
unsigned8 header_size,
rpc_socket_iovec_p_t iov,
unsigned32 iovlen,
rpc_socket_iovec_p_t out_iov,
unsigned32 *st
)
{
rpc_cn_common_hdr_p_t pdu;
unsigned32 i;
unsigned32 pdu_buflen;
unsigned_char_p_t pdu_buf, pdu_bufp;
OM_uint32 min_stat;
gss_buffer_desc output_token;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_create_large_frag)\n"));
output_token.length = assoc_sec->krb_message.length;
output_token.value = assoc_sec->krb_message.data;
assoc_sec->krb_message.length = 0;
assoc_sec->krb_message.data = NULL;
if (iovlen < 1) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_create_large_frag): %s: iovlen[%u]\n",
comment, (unsigned int)iovlen));
gss_release_buffer(&min_stat, &output_token);
*st = rpc_m_no_stub_data;
return;
}
if (iov[0].iov_len < header_size) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_create_large_frag): %s: iov[0].iov_len[%u] < header_size[%u]\n",
comment, (unsigned int)iov[0].iov_len,(unsigned int)header_size));
gss_release_buffer(&min_stat, &output_token);
*st = rpc_m_no_stub_data;
return;
}
for (i = 0, pdu_buflen = 0; i < iovlen; i++) {
pdu_buflen += iov[i].iov_len;
}
if (pdu_buflen < header_size + RPC_CN_PKT_SIZEOF_COM_AUTH_TLR + output_token.length) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_create_large_frag): %s: pdu_buflen[%u] < min_len[%u]\n",
comment, (unsigned int)pdu_buflen,
(unsigned int)header_size +
RPC_CN_PKT_SIZEOF_COM_AUTH_TLR + (unsigned int)output_token.length));
gss_release_buffer(&min_stat, &output_token);
*st = rpc_m_no_stub_data;
return;
}
pdu_buflen += output_token.length;
RPC_MEM_ALLOC(pdu_buf,
unsigned_char_p_t,
pdu_buflen,
RPC_C_MEM_CN_ENCRYPT_BUF,
RPC_C_MEM_WAITOK);
pdu_bufp = pdu_buf;
pdu = (rpc_cn_common_hdr_p_t)pdu_bufp;
for (i = 0; i < iovlen; i++) {
memcpy(pdu_bufp, iov[i].iov_base, iov[i].iov_len);
pdu_bufp += iov[i].iov_len;
}
memcpy(pdu_bufp, output_token.value, output_token.length);
pdu_bufp += output_token.length;
pdu->frag_len = (pdu_bufp - pdu_buf);
pdu->auth_len = output_token.length;
out_iov->iov_base = pdu_buf;
out_iov->iov_len = pdu_buflen;
assert(out_iov->iov_len == pdu->frag_len);
gss_release_buffer(&min_stat, &output_token);
*st = rpc_s_ok;
}
INTERNAL void rpc__gssauth_cn_pre_send
(
rpc_cn_assoc_sec_context_p_t assoc_sec,
rpc_cn_sec_context_p_t sec,
rpc_socket_iovec_p_t iov,
unsigned32 iovlen,
rpc_socket_iovec_p_t out_iov,
unsigned32 *st
)
{
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
rpc_cn_common_hdr_p_t pdu;
rpc_cn_packet_p_t pkt;
unsigned32 ptype;
boolean conf_req_flag = false;
OM_uint32 min_stat;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_pre_send)\n"));
pdu = (rpc_cn_common_hdr_p_t)iov[0].iov_base;
pkt = (rpc_cn_packet_p_t)pdu;
ptype = pdu->ptype;
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_pre_send) authn level->%x packet type->%x\n",
sec->sec_info->authn_level, ptype));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_pre_send) prot->%x level->%x key_id->%x assoc_uuid_crc->%x xmit_seq->%x recv_seq->%x ptype->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id,
assoc_sec->assoc_uuid_crc,
assoc_sec->assoc_next_snd_seq,
assoc_sec->assoc_next_rcv_seq,
ptype));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_PRE_SEND)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
out_iov->iov_base = NULL;
switch (ptype) {
case RPC_C_CN_PKT_REQUEST:
case RPC_C_CN_PKT_RESPONSE:
switch (sec->sec_info->authn_level) {
case rpc_c_authn_level_connect:
*st = rpc_s_ok;
break;
case rpc_c_authn_level_pkt_privacy:
conf_req_flag = true;
case rpc_c_authn_level_pkt_integrity:
rpc__gssauth_cn_wrap_packet(sec,
ptype == RPC_C_CN_PKT_REQUEST ? "request" : "response",
ptype == RPC_C_CN_PKT_REQUEST ? RPC_CN_PKT_SIZEOF_RQST_HDR :
RPC_CN_PKT_SIZEOF_RESP_HDR,
iov, iovlen, conf_req_flag, out_iov, st);
break;
default:
break;
}
break;
case RPC_C_CN_PKT_BIND:
case RPC_C_CN_PKT_ALTER_CONTEXT:
if (!getenv("DCE_DISABLE_HEADER_SIGN")) {
RPC_CN_PKT_FLAGS(pkt) |= RPC_C_CN_FLAGS_SUPPORT_HEADER_SIGN;
}
if (assoc_sec->krb_message.length == 0) {
*st = rpc_s_ok;
} else {
rpc__gssauth_cn_create_large_frag(assoc_sec,
(ptype == RPC_C_CN_PKT_BIND) ? "bind" : "alter_context",
RPC_CN_PKT_SIZEOF_BIND_HDR,
iov, iovlen, out_iov, st);
}
break;
case RPC_C_CN_PKT_BIND_ACK:
case RPC_C_CN_PKT_BIND_NAK:
case RPC_C_CN_PKT_ALTER_CONTEXT_RESP:
if (gssauth_cn_info->header_sign)
RPC_CN_PKT_FLAGS(pkt) |= RPC_C_CN_FLAGS_SUPPORT_HEADER_SIGN;
break;
case RPC_C_CN_PKT_AUTH3: {
gss_buffer_desc input_token, output_token;
rpc_cn_auth_tlr_p_t auth_tlr;
if (sec->sec_info->is_server)
break;
assert(iovlen == 1);
auth_tlr = RPC_CN_PKT_AUTH_TLR(pkt, iov[0].iov_len);
input_token.value = auth_tlr->auth_value;
input_token.length = RPC_CN_PKT_AUTH_LEN(pkt);
(void) rpc__gssauth_verify_server_token(&min_stat,
sec,
GSS_C_NO_CREDENTIAL,
GSS_C_NO_NAME,
gssauth_cn_info->gss_ctx,
input_token,
&gssauth_cn_info->gss_mech,
&output_token);
if (output_token.length) {
*st = rpc_s_credentials_too_large;
gss_release_buffer(&min_stat, &output_token);
return;
}
break;
}
case RPC_C_CN_PKT_FAULT:
case RPC_C_CN_PKT_SHUTDOWN:
case RPC_C_CN_PKT_REMOTE_ALERT:
case RPC_C_CN_PKT_ORPHANED:
default:
break;
}
}
INTERNAL void rpc__gssauth_cn_unwrap_packet
(
rpc_cn_sec_context_p_t sec,
const char *comment,
unsigned8 header_size,
rpc_cn_common_hdr_p_t pdu,
unsigned32 pdu_len,
unsigned32 cred_len ATTRIBUTE_UNUSED,
rpc_cn_auth_tlr_p_t auth_tlr,
boolean conf_req_flag,
boolean32 unpack_ints,
unsigned32 *st
)
{
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
OM_uint32 maj_stat;
OM_uint32 min_stat;
int conf_state;
gss_qop_t qop_state;
unsigned16 auth_len;
gss_iov_buffer_desc gss_iov[4];
boolean header_sign = gssauth_cn_info->header_sign;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_unwrap_packet)\n"));
auth_len = pdu->auth_len;
if (unpack_ints) {
SWAB_INPLACE_16(auth_len);
}
gss_iov[0].type = header_sign ? GSS_IOV_BUFFER_TYPE_SIGN_ONLY :
GSS_IOV_BUFFER_TYPE_EMPTY;
gss_iov[0].buffer.value = (unsigned_char_p_t)pdu;
gss_iov[0].buffer.length = header_size;
gss_iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
gss_iov[1].buffer.value = (unsigned_char_p_t)pdu + header_size;
gss_iov[1].buffer.length = pdu_len -
(header_size + RPC_CN_PKT_SIZEOF_COM_AUTH_TLR + auth_len);
gss_iov[2].type = header_sign ? GSS_IOV_BUFFER_TYPE_SIGN_ONLY :
GSS_IOV_BUFFER_TYPE_EMPTY;
gss_iov[2].buffer.value = auth_tlr;
gss_iov[2].buffer.length = RPC_CN_PKT_SIZEOF_COM_AUTH_TLR;
gss_iov[3].type = GSS_IOV_BUFFER_TYPE_HEADER;
gss_iov[3].buffer.value = (unsigned_char_p_t)auth_tlr +
RPC_CN_PKT_SIZEOF_COM_AUTH_TLR;
gss_iov[3].buffer.length = auth_len;
if (conf_req_flag) {
maj_stat = gss_unwrap_iov(&min_stat,
gssauth_cn_info->gss_ctx,
&conf_state,
&qop_state,
gss_iov,
sizeof(gss_iov)/sizeof(gss_iov[0]));
} else {
gss_buffer_desc input_token;
conf_state = 0;
if (header_sign) {
input_token = gss_iov[0].buffer;
input_token.length += gss_iov[1].buffer.length + gss_iov[2].buffer.length;
} else {
input_token = gss_iov[1].buffer;
}
maj_stat = gss_verify_mic(&min_stat,
gssauth_cn_info->gss_ctx,
&input_token,
&gss_iov[3].buffer,
&qop_state);
}
if (maj_stat != GSS_S_COMPLETE) {
char msg[BUFSIZ];
rpc__gssauth_error_map(maj_stat, min_stat,
gssauth_cn_info->gss_mech,
msg, sizeof(msg), st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_unwrap_packet): %s: %s\n",
comment, msg));
} else if (conf_state != conf_req_flag) {
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_unwrap_packet): %s: packet privacy mismatch\n",
comment));
*st = rpc_s_auth_bad_integrity;
} else {
*st = rpc_s_ok;
}
return;
}
INTERNAL void rpc__gssauth_cn_recv_check
(
rpc_cn_assoc_sec_context_p_t assoc_sec,
rpc_cn_sec_context_p_t sec,
rpc_cn_common_hdr_p_t pdu,
unsigned32 pdu_len,
unsigned32 cred_len,
rpc_cn_auth_tlr_p_t auth_tlr,
boolean32 unpack_ints,
unsigned32 *st
)
{
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
boolean conf_req_flag = false;
rpc_cn_packet_p_t pkt = (rpc_cn_packet_p_t)pdu;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_recv_check)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_recv_check) authn level->%x packet type->%x\n",
sec->sec_info->authn_level,
pdu->ptype));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_recv_check) prot->%x level->%x key_id->%x assoc_uuid_crc->%x xmit_seq->%x recv_seq->%x ptype->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id,
assoc_sec->assoc_uuid_crc,
assoc_sec->assoc_next_snd_seq,
assoc_sec->assoc_next_rcv_seq,
pdu->ptype));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_RECV_CHECK)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
switch (pdu->ptype) {
case RPC_C_CN_PKT_REQUEST:
case RPC_C_CN_PKT_RESPONSE:
switch (sec->sec_info->authn_level) {
case rpc_c_authn_level_connect:
*st = rpc_s_ok;
break;
case rpc_c_authn_level_pkt_privacy:
conf_req_flag = true;
case rpc_c_authn_level_pkt_integrity:
rpc__gssauth_cn_unwrap_packet(sec,
(pdu->ptype == RPC_C_CN_PKT_REQUEST) ? "request" : "response",
(pdu->ptype == RPC_C_CN_PKT_REQUEST) ? RPC_CN_PKT_SIZEOF_RQST_HDR : RPC_CN_PKT_SIZEOF_RESP_HDR,
pdu, pdu_len, cred_len, auth_tlr, conf_req_flag,
unpack_ints, st);
break;
}
break;
case RPC_C_CN_PKT_AUTH3:
case RPC_C_CN_PKT_BIND:
case RPC_C_CN_PKT_BIND_ACK:
case RPC_C_CN_PKT_BIND_NAK:
case RPC_C_CN_PKT_ALTER_CONTEXT:
case RPC_C_CN_PKT_ALTER_CONTEXT_RESP:
if (RPC_CN_PKT_FLAGS(pkt) & RPC_C_CN_FLAGS_SUPPORT_HEADER_SIGN)
gssauth_cn_info->header_sign = true;
case RPC_C_CN_PKT_SHUTDOWN:
case RPC_C_CN_PKT_REMOTE_ALERT:
case RPC_C_CN_PKT_ORPHANED:
case RPC_C_CN_PKT_FAULT:
default:
*st = rpc_s_ok;
break;
}
}
INTERNAL void rpc__gssauth_cn_tlr_uuid_crc
(
dce_pointer_t auth_value ATTRIBUTE_UNUSED ,
unsigned32 auth_value_len ATTRIBUTE_UNUSED ,
unsigned32 *uuid_crc
)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_tlr_uuid_crc)\n"));
*uuid_crc = 0;
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_tlr_uuid_crc) assoc_uuid_crc->%x\n", *uuid_crc));
}
INTERNAL void rpc__gssauth_cn_tlr_unpack
(
rpc_cn_packet_p_t pkt_p ATTRIBUTE_UNUSED ,
unsigned32 auth_value_len ATTRIBUTE_UNUSED ,
unsigned8 *packed_drep ATTRIBUTE_UNUSED
)
{
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_tlr_unpack)\n"));
}
INTERNAL void rpc__gssauth_cn_vfy_client_req
(
rpc_cn_assoc_sec_context_p_t assoc_sec,
rpc_cn_sec_context_p_t sec,
dce_pointer_t auth_value,
unsigned32 auth_value_len,
unsigned32 old_client ATTRIBUTE_UNUSED ,
unsigned32 *st
)
{
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
int maj_stat;
OM_uint32 min_stat = 0;
gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_vfy_client_req)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_vfy_client_req) prot->%x level->%x key_id->%x assoc_uuid_crc->%x xmit_seq->%x recv_seq->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id,
assoc_sec->assoc_uuid_crc,
assoc_sec->assoc_next_snd_seq,
assoc_sec->assoc_next_rcv_seq));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_VFY_CLIENT_REQ)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
input_token.value = auth_value;
input_token.length = auth_value_len;
maj_stat = gss_accept_sec_context(&min_stat,
&gssauth_cn_info->gss_ctx,
NULL,
&input_token,
NULL,
NULL,
&gssauth_cn_info->gss_mech,
&output_token,
NULL,
NULL,
NULL);
gssauth_cn_info->gss_stat = maj_stat;
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
char msg[BUFSIZ];
rpc__gssauth_error_map(maj_stat, min_stat,
gssauth_cn_info->gss_mech,
msg, sizeof(msg), st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_vfy_client_req): %s: output_token.length[%u]\n",
msg, (unsigned int)output_token.length));
} else if (maj_stat != GSS_S_COMPLETE) {
char msg[BUFSIZ];
rpc__gssauth_error_map(maj_stat, min_stat,
gssauth_cn_info->gss_mech,
msg, sizeof(msg), st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_vfy_client_req): %s\n", msg));
return;
} else {
*st = rpc_s_ok;
}
assoc_sec->krb_message.length = (unsigned32) output_token.length;
assoc_sec->krb_message.data = output_token.value;
}
INTERNAL void rpc__gssauth_cn_vfy_srvr_resp
(
rpc_cn_assoc_sec_context_p_t assoc_sec,
rpc_cn_sec_context_p_t sec,
dce_pointer_t auth_value,
unsigned32 auth_value_len,
unsigned32 *st
)
{
rpc_gssauth_info_p_t gssauth_info = (rpc_gssauth_info_p_t)sec->sec_info;
rpc_gssauth_cn_info_p_t gssauth_cn_info = (rpc_gssauth_cn_info_p_t)sec->sec_cn_info;
OM_uint32 maj_stat;
OM_uint32 min_stat;
gss_buffer_desc input_token, output_token = GSS_C_EMPTY_BUFFER;
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_cn_vfy_srvr_resp)\n"));
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_PKT,
("(rpc__gssauth_cn_vfy_server_resp) prot->%x level->%x key_id->%x assoc_uuid_crc->%x xmit_seq->%x recv_seq->%x\n",
sec->sec_info->authn_protocol,
sec->sec_info->authn_level,
sec->sec_key_id,
assoc_sec->assoc_uuid_crc,
assoc_sec->assoc_next_snd_seq,
assoc_sec->assoc_next_rcv_seq));
#ifdef DEBUG
if (RPC_DBG_EXACT(rpc_es_dbg_cn_errors, RPC_C_CN_DBG_AUTH_VFY_SERVER_RESP)) {
*st = RPC_S_CN_DBG_AUTH_FAILURE;
return;
}
#endif
if (gssauth_cn_info->gss_ctx != GSS_C_NO_CONTEXT &&
gssauth_cn_info->gss_stat == GSS_S_COMPLETE) {
goto done;
}
input_token.value = auth_value;
input_token.length = auth_value_len;
maj_stat = rpc__gssauth_verify_server_token(&min_stat,
sec,
gssauth_info->gss_creds,
gssauth_info->gss_server_name,
gssauth_cn_info->gss_ctx,
input_token,
&gssauth_cn_info->gss_mech,
&output_token);
gssauth_cn_info->gss_stat = maj_stat;
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
char msg[BUFSIZ];
rpc__gssauth_error_map(maj_stat, min_stat,
gssauth_cn_info->gss_mech,
msg, sizeof(msg), st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_vfy_srvr_resp): %s: output_token.length[%u]\n",
msg, (unsigned int)output_token.length));
} else if (maj_stat != GSS_S_COMPLETE) {
char msg[BUFSIZ];
rpc__gssauth_error_map(maj_stat, min_stat,
gssauth_cn_info->gss_mech,
msg, sizeof(msg), st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL,
("(rpc__gssauth_cn_vfy_srvr_resp): %s\n", msg));
return;
}
done:
assoc_sec->krb_message.length = (unsigned32) output_token.length;
assoc_sec->krb_message.data = output_token.value;
*st = rpc_s_ok;
}
PRIVATE rpc_protocol_id_t rpc__gssauth_negotiate_cn_init
(
rpc_auth_rpc_prot_epv_p_t *epv,
unsigned32 *st
)
{
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_negotiate_cn_init)\n"));
*epv = (rpc_auth_rpc_prot_epv_p_t)&rpc_g_gssauth_negotiate_cn_epv;
*st = rpc_s_ok;
return RPC_C_PROTOCOL_ID_NCACN;
}
PRIVATE rpc_protocol_id_t rpc__gssauth_mskrb_cn_init
(
rpc_auth_rpc_prot_epv_p_t *epv,
unsigned32 *st
)
{
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_mskrb_cn_init)\n"));
*epv = (rpc_auth_rpc_prot_epv_p_t)&rpc_g_gssauth_mskrb_cn_epv;
*st = rpc_s_ok;
return RPC_C_PROTOCOL_ID_NCACN;
}
PRIVATE rpc_protocol_id_t rpc__gssauth_winnt_cn_init
(
rpc_auth_rpc_prot_epv_p_t *epv,
unsigned32 *st
)
{
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_winnt_cn_init)\n"));
*epv = (rpc_auth_rpc_prot_epv_p_t)&rpc_g_gssauth_winnt_cn_epv;
*st = rpc_s_ok;
return RPC_C_PROTOCOL_ID_NCACN;
}
PRIVATE rpc_protocol_id_t rpc__gssauth_netlogon_cn_init
(
rpc_auth_rpc_prot_epv_p_t *epv,
unsigned32 *st
)
{
CODING_ERROR(st);
RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE,
("(rpc__gssauth_netlogon_cn_init)\n"));
*epv = (rpc_auth_rpc_prot_epv_p_t)&rpc_g_gssauth_netlogon_cn_epv;
*st = rpc_s_ok;
return RPC_C_PROTOCOL_ID_NCACN;
}
#endif