diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asn1c/BOOLEAN.c | 282 | ||||
-rw-r--r-- | src/asn1c/BOOLEAN.h | 36 | ||||
-rw-r--r-- | src/asn1c/GSSSessionData.c | 36 | ||||
-rw-r--r-- | src/asn1c/GSSSessionData.h | 3 | ||||
-rw-r--r-- | src/asn1c/Makefile.am | 2 | ||||
-rw-r--r-- | src/asn1c/session.asn1 | 8 | ||||
-rw-r--r-- | src/mod_auth_gssapi.c | 64 | ||||
-rw-r--r-- | src/mod_auth_gssapi.h | 1 | ||||
-rw-r--r-- | src/sessions.c | 6 |
9 files changed, 412 insertions, 26 deletions
diff --git a/src/asn1c/BOOLEAN.c b/src/asn1c/BOOLEAN.c new file mode 100644 index 0000000..1b74ea1 --- /dev/null +++ b/src/asn1c/BOOLEAN.c @@ -0,0 +1,282 @@ +/*- + * Copyright (c) 2003, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include <asn_internal.h> +#include <asn_codecs_prim.h> +#include <BOOLEAN.h> + +/* + * BOOLEAN basic type description. + */ +static ber_tlv_tag_t asn_DEF_BOOLEAN_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (1 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_BOOLEAN = { + "BOOLEAN", + "BOOLEAN", + BOOLEAN_free, + BOOLEAN_print, + asn_generic_no_constraint, + BOOLEAN_decode_ber, + BOOLEAN_encode_der, + BOOLEAN_decode_xer, + BOOLEAN_encode_xer, + BOOLEAN_decode_uper, /* Unaligned PER decoder */ + BOOLEAN_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_BOOLEAN_tags, + sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]), + asn_DEF_BOOLEAN_tags, /* Same as above */ + sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Decode BOOLEAN type. + */ +asn_dec_rval_t +BOOLEAN_decode_ber(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **bool_value, const void *buf_ptr, size_t size, + int tag_mode) { + BOOLEAN_t *st = (BOOLEAN_t *)*bool_value; + asn_dec_rval_t rval; + ber_tlv_len_t length; + ber_tlv_len_t lidx; + + if(st == NULL) { + st = (BOOLEAN_t *)(*bool_value = CALLOC(1, sizeof(*st))); + if(st == NULL) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + } + + ASN_DEBUG("Decoding %s as BOOLEAN (tm=%d)", + td->name, tag_mode); + + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("Boolean length is %d bytes", (int)length); + + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + /* + * Compute boolean value. + */ + for(*st = 0, lidx = 0; + (lidx < length) && *st == 0; lidx++) { + /* + * Very simple approach: read bytes until the end or + * value is already TRUE. + * BOOLEAN is not supposed to contain meaningful data anyway. + */ + *st |= ((const uint8_t *)buf_ptr)[lidx]; + } + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s, value=%d", + (long)rval.consumed, (long)length, + td->name, *st); + + return rval; +} + +asn_enc_rval_t +BOOLEAN_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t erval; + BOOLEAN_t *st = (BOOLEAN_t *)sptr; + + erval.encoded = der_write_tags(td, 1, tag_mode, 0, tag, cb, app_key); + if(erval.encoded == -1) { + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + + if(cb) { + uint8_t bool_value; + + bool_value = *st ? 0xff : 0; /* 0xff mandated by DER */ + + if(cb(&bool_value, 1, app_key) < 0) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + } + + erval.encoded += 1; + + _ASN_ENCODED_OK(erval); +} + + +/* + * Decode the chunk of XML text encoding INTEGER. + */ +static enum xer_pbd_rval +BOOLEAN__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { + BOOLEAN_t *st = (BOOLEAN_t *)sptr; + const char *p = (const char *)chunk_buf; + + (void)td; + + if(chunk_size && p[0] == 0x3c /* '<' */) { + switch(xer_check_tag(chunk_buf, chunk_size, "false")) { + case XCT_BOTH: + /* "<false/>" */ + *st = 0; + break; + case XCT_UNKNOWN_BO: + if(xer_check_tag(chunk_buf, chunk_size, "true") + != XCT_BOTH) + return XPBD_BROKEN_ENCODING; + /* "<true/>" */ + *st = 1; /* Or 0xff as in DER?.. */ + break; + default: + return XPBD_BROKEN_ENCODING; + } + return XPBD_BODY_CONSUMED; + } else { + return XPBD_BROKEN_ENCODING; + } +} + + +asn_dec_rval_t +BOOLEAN_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(BOOLEAN_t), opt_mname, buf_ptr, size, + BOOLEAN__xer_body_decode); +} + +asn_enc_rval_t +BOOLEAN_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + asn_enc_rval_t er; + + (void)ilevel; + (void)flags; + + if(!st) _ASN_ENCODE_FAILED; + + if(*st) { + _ASN_CALLBACK("<true/>", 7); + er.encoded = 7; + } else { + _ASN_CALLBACK("<false/>", 8); + er.encoded = 8; + } + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} + +int +BOOLEAN_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + const char *buf; + size_t buflen; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(st) { + if(*st) { + buf = "TRUE"; + buflen = 4; + } else { + buf = "FALSE"; + buflen = 5; + } + } else { + buf = "<absent>"; + buflen = 8; + } + + return (cb(buf, buflen, app_key) < 0) ? -1 : 0; +} + +void +BOOLEAN_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + if(td && ptr && !contents_only) { + FREEMEM(ptr); + } +} + +asn_dec_rval_t +BOOLEAN_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + BOOLEAN_t *st = (BOOLEAN_t *)*sptr; + + (void)opt_codec_ctx; + (void)constraints; + + if(!st) { + st = (BOOLEAN_t *)(*sptr = MALLOC(sizeof(*st))); + if(!st) _ASN_DECODE_FAILED; + } + + /* + * Extract a single bit + */ + switch(per_get_few_bits(pd, 1)) { + case 1: *st = 1; break; + case 0: *st = 0; break; + case -1: default: _ASN_DECODE_STARVED; + } + + ASN_DEBUG("%s decoded as %s", td->name, *st ? "TRUE" : "FALSE"); + + rv.code = RC_OK; + rv.consumed = 1; + return rv; +} + + +asn_enc_rval_t +BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + asn_enc_rval_t er = { 0, 0, 0 }; + + (void)constraints; + + if(!st) _ASN_ENCODE_FAILED; + + if(per_put_few_bits(po, *st ? 1 : 0, 1)) + _ASN_ENCODE_FAILED; + + _ASN_ENCODED_OK(er); +} diff --git a/src/asn1c/BOOLEAN.h b/src/asn1c/BOOLEAN.h new file mode 100644 index 0000000..217d0f1 --- /dev/null +++ b/src/asn1c/BOOLEAN.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BOOLEAN_H_ +#define _BOOLEAN_H_ + +#include <asn_application.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The underlying integer may contain various values, but everything + * non-zero is capped to 0xff by the DER encoder. The BER decoder may + * yield non-zero values different from 1, beware. + */ +typedef int BOOLEAN_t; + +extern asn_TYPE_descriptor_t asn_DEF_BOOLEAN; + +asn_struct_free_f BOOLEAN_free; +asn_struct_print_f BOOLEAN_print; +ber_type_decoder_f BOOLEAN_decode_ber; +der_type_encoder_f BOOLEAN_encode_der; +xer_type_decoder_f BOOLEAN_decode_xer; +xer_type_encoder_f BOOLEAN_encode_xer; +per_type_decoder_f BOOLEAN_decode_uper; +per_type_encoder_f BOOLEAN_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _BOOLEAN_H_ */ diff --git a/src/asn1c/GSSSessionData.c b/src/asn1c/GSSSessionData.c index 5c8ec17..0f20581 100644 --- a/src/asn1c/GSSSessionData.c +++ b/src/asn1c/GSSSessionData.c @@ -8,9 +8,27 @@ #include "GSSSessionData.h" static asn_TYPE_member_t asn_MBR_GSSSessionData_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, expiration), + { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, established), (ASN_TAG_CLASS_CONTEXT | (0 << 2)), +1, /* EXPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "established" + }, + { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, delegated), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_BOOLEAN, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "delegated" + }, + { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, expiration), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + +1, /* EXPLICIT tag at current level */ &asn_DEF_Uint32, 0, /* Defer constraints checking to the member type */ 0, /* PER is not compiled, use -gen-PER */ @@ -18,7 +36,7 @@ static asn_TYPE_member_t asn_MBR_GSSSessionData_1[] = { "expiration" }, { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, username), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), +1, /* EXPLICIT tag at current level */ &asn_DEF_OCTET_STRING, 0, /* Defer constraints checking to the member type */ @@ -27,7 +45,7 @@ static asn_TYPE_member_t asn_MBR_GSSSessionData_1[] = { "username" }, { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, gssname), - (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), +1, /* EXPLICIT tag at current level */ &asn_DEF_OCTET_STRING, 0, /* Defer constraints checking to the member type */ @@ -40,15 +58,17 @@ static ber_tlv_tag_t asn_DEF_GSSSessionData_tags_1[] = { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) }; static asn_TYPE_tag2member_t asn_MAP_GSSSessionData_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* expiration */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* username */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* gssname */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* established */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* delegated */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* expiration */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* username */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 } /* gssname */ }; static asn_SEQUENCE_specifics_t asn_SPC_GSSSessionData_specs_1 = { sizeof(struct GSSSessionData), offsetof(struct GSSSessionData, _asn_ctx), asn_MAP_GSSSessionData_tag2el_1, - 3, /* Count of tags in the map */ + 5, /* Count of tags in the map */ 0, 0, 0, /* Optional elements (not needed) */ -1, /* Start extensions */ -1 /* Stop extensions */ @@ -73,7 +93,7 @@ asn_TYPE_descriptor_t asn_DEF_GSSSessionData = { /sizeof(asn_DEF_GSSSessionData_tags_1[0]), /* 1 */ 0, /* No PER visible constraints */ asn_MBR_GSSSessionData_1, - 3, /* Elements count */ + 5, /* Elements count */ &asn_SPC_GSSSessionData_specs_1 /* Additional specs */ }; diff --git a/src/asn1c/GSSSessionData.h b/src/asn1c/GSSSessionData.h index b4e2e45..423996f 100644 --- a/src/asn1c/GSSSessionData.h +++ b/src/asn1c/GSSSessionData.h @@ -12,6 +12,7 @@ #include <asn_application.h> /* Including external dependencies */ +#include <BOOLEAN.h> #include "Uint32.h" #include <OCTET_STRING.h> #include <constr_SEQUENCE.h> @@ -22,6 +23,8 @@ extern "C" { /* GSSSessionData */ typedef struct GSSSessionData { + BOOLEAN_t established; + BOOLEAN_t delegated; Uint32_t expiration; OCTET_STRING_t username; OCTET_STRING_t gssname; diff --git a/src/asn1c/Makefile.am b/src/asn1c/Makefile.am index 8d6c81d..d116e58 100644 --- a/src/asn1c/Makefile.am +++ b/src/asn1c/Makefile.am @@ -6,6 +6,7 @@ ASN1C_SOURCES = \ ber_tlv_length.c \ ber_tlv_tag.c \ BIT_STRING.c \ + BOOLEAN.c \ constraints.c \ constr_SEQUENCE.c \ constr_TYPE.c \ @@ -30,6 +31,7 @@ ASN1C_SOURCES = \ ber_tlv_length.h \ ber_tlv_tag.h \ BIT_STRING.h \ + BOOLEAN.h \ constraints.h \ constr_SEQUENCE.h \ constr_TYPE.h \ diff --git a/src/asn1c/session.asn1 b/src/asn1c/session.asn1 index 8f17e47..8d7b4e5 100644 --- a/src/asn1c/session.asn1 +++ b/src/asn1c/session.asn1 @@ -3,8 +3,10 @@ GssapiSessionModule DEFINITIONS ::= BEGIN Uint32 ::= INTEGER (0..4294967295) GSSSessionData ::= SEQUENCE { - expiration [0] Uint32, - username [1] OCTET STRING, - gssname [2] OCTET STRING + established [0] BOOLEAN, + delegated [1] BOOLEAN, + expiration [2] Uint32, + username [3] OCTET STRING, + gssname [4] OCTET STRING } END diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index a88b653..79d62cd 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -191,33 +191,54 @@ static char *escape(apr_pool_t *pool, const char *name, return escaped; } -static void mag_store_deleg_creds(request_rec *req, - char *dir, char *clientname, - gss_cred_id_t delegated_cred, - char **ccachefile) +static char *mag_gss_name_to_ccache_name(request_rec *req, + char *dir, const char *gss_name) { - gss_key_value_element_desc element; - gss_key_value_set_desc store; - char *value; - uint32_t maj, min; char *escaped; /* We need to escape away '/', we can't have path separators in * a ccache file name */ /* first double escape the esacping char (~) if any */ - escaped = escape(req->pool, clientname, '~', "~~"); - if (!escaped) return; + escaped = escape(req->pool, gss_name, '~', "~~"); /* then escape away the separator (/) if any */ escaped = escape(req->pool, escaped, '/', "~"); - if (!escaped) return; - value = apr_psprintf(req->pool, "FILE:%s/%s", dir, escaped); + return apr_psprintf(req->pool, "%s/%s", dir, escaped); +} + +static void mag_set_KRB5CCANME(request_rec *req, char *ccname) +{ + apr_status_t status; + apr_finfo_t finfo; + char *value; + status = apr_stat(&finfo, ccname, APR_FINFO_MIN, req->pool); + if (status != APR_SUCCESS && status != APR_INCOMPLETE) { + /* set the file cache anyway, but warn */ + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, + "KRB5CCNAME file (%s) lookup failed!", ccname); + } + + value = apr_psprintf(req->pool, "FILE:%s", ccname); + apr_table_set(req->subprocess_env, "KRB5CCNAME", value); +} + +static void mag_store_deleg_creds(request_rec *req, + char *dir, char *clientname, + gss_cred_id_t delegated_cred, + char **ccachefile) +{ + gss_key_value_element_desc element; + gss_key_value_set_desc store; + char *ccname; + uint32_t maj, min; element.key = "ccache"; - element.value = value; store.elements = &element; store.count = 1; + ccname = mag_gss_name_to_ccache_name(req, dir, clientname); + element.value = apr_psprintf(req->pool, "FILE:%s", ccname); + maj = gss_store_cred_into(&min, delegated_cred, GSS_C_INITIATE, GSS_C_NULL_OID, 1, 1, &store, NULL, NULL); if (GSS_ERROR(maj)) { @@ -226,7 +247,7 @@ static void mag_store_deleg_creds(request_rec *req, maj, min)); } - *ccachefile = value; + *ccachefile = ccname; } #endif @@ -392,6 +413,15 @@ static int mag_auth(request_rec *req) req->ap_auth_type = apr_pstrdup(req->pool, auth_types[mc->auth_type]); req->user = apr_pstrdup(req->pool, mc->user_name); + if (cfg->deleg_ccache_dir && mc->delegated) { + char *ccname; + ccname = mag_gss_name_to_ccache_name(req, + cfg->deleg_ccache_dir, + mc->gss_name); + if (ccname) { + mag_set_KRB5CCANME(req, ccname); + } + } ret = OK; goto done; } @@ -644,7 +674,11 @@ static int mag_auth(request_rec *req) delegated_cred, &ccachefile); if (ccachefile) { - apr_table_set(req->subprocess_env, "KRB5CCNAME", ccachefile); + mag_set_KRB5CCANME(req, ccachefile); + } + + if (mc) { + mc->delegated = true; } } #endif diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h index 103ec61..97ba2c8 100644 --- a/src/mod_auth_gssapi.h +++ b/src/mod_auth_gssapi.h @@ -67,6 +67,7 @@ struct mag_conn { const char *gss_name; time_t expiration; int auth_type; + bool delegated; }; #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) diff --git a/src/sessions.c b/src/sessions.c index e8c79cd..f90857c 100644 --- a/src/sessions.c +++ b/src/sessions.c @@ -153,6 +153,10 @@ void mag_check_session(request_rec *req, return; } + /* booleans */ + if (gsessdata->established != 0) mc->established = true; + if (gsessdata->delegated != 0) mc->delegated = true; + /* get time */ expiration = gsessdata->expiration; if (expiration < time(NULL)) { @@ -211,6 +215,8 @@ void mag_attempt_session(request_rec *req, } } + gsessdata.established = mc->established?1:0; + gsessdata.delegated = mc->delegated?1:0; gsessdata.expiration = mc->expiration; if (OCTET_STRING_fromString(&gsessdata.username, mc->user_name) != 0) goto done; |