pax_global_header00006660000000000000000000000064126612223460014516gustar00rootroot0000000000000052 comment=faf9ee7750331a8db0a6f699949f7c5d62940f20 mod_auth_gssapi-1.3.2/000077500000000000000000000000001266122234600146675ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/.gitignore000066400000000000000000000003431266122234600166570ustar00rootroot00000000000000Makefile Makefile.in aclocal.m4 ar-lib autom4te.cache compile config.guess config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh m4/ missing .deps .libs config.h config.h.in* stamp-h1 *.o *.lo *.la mod_auth_gssapi-1.3.2/AUTHORS000066400000000000000000000000351266122234600157350ustar00rootroot00000000000000Simo Sorce mod_auth_gssapi-1.3.2/COPYING000066400000000000000000000020631266122234600157230ustar00rootroot00000000000000MOD_AUTH_GSSAPI Copyright (C) 2014 Red Hat, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mod_auth_gssapi-1.3.2/ChangeLog000066400000000000000000000000001266122234600164270ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/Makefile.am000066400000000000000000000001211266122234600167150ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -I m4 SUBDIRS = src/asn1c src test: all ./tests/magtests.py mod_auth_gssapi-1.3.2/NEWS000066400000000000000000000000001266122234600153540ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/README000066400000000000000000000237421266122234600155570ustar00rootroot00000000000000mod_auth_gssapi =============== Intro ----- This module has been built as a replacement for the aging mod_auth_kerb. Its aim is to use only GSSAPI calls and be as much as possible agnostic of the actual mechanism used. Dependencies ------------ A modern version of MIT's Krb5 distribution or any GSSAPI implementation that supports the [credential store extension](http://k5wiki.kerberos.org/wiki/Projects/Credential_Store_extensions) is necessary to achieve full functionality. Reduced functionality is provided without these extensions. krb5 (>=1.11) Apache (>=2.4) ### Tests To run tests, you also need: * The Kerberos 5 Key-Distribution-Center (`krb5-kdc` package on Debian) * [nss_wrapper](https://cwrap.org/nss_wrapper.html) * [socket_wrapper](https://cwrap.org/socket_wrapper.html) Installation ------------ ./configure make make install Configuration ------------- Apache authentication modules are usually configured per location, see the [mod_authn_core](https://httpd.apache.org/docs/2.4/mod/mod_authn_core.html) documentation for the common directives ### Basic configuration The simplest configuration scheme specifies just one directive, which is the location of the keytab. #### Example AuthType GSSAPI AuthName "GSSAPI Single Sign On Login" GssapiCredStore keytab:/etc/httpd.keytab Require valid-user Your Apache server need read access to the keytab configured. If your Kerberos implementation does not support the credential store extensions you can also simply set the KRB5_KTNAME environment variable in the Apache init script and skip the GssapiCredStore option completely. Configuration Directives ------------------------ ### GssapiSSLonly Forces the authentication attempt to fail if the connection is not being established over TLS #### Example GssapiSSLonly On ### GssapiLocalName Tries to map the client principal to a local name using the gss_localname() call. This requires configuration in the /etc/krb5.conf file in order to allow proper mapping for principals not in the default realm (for example a user coming from a trusted realm). See the 'auth_to_local' option in the [realms] section of krb5.conf(5) When this options is used the resolved name is set in the REMOTE_USER variable however the complete client principal name is also made available in the GSS_NAME variable. #### Example GssapiLocalName on ### GssapiConnectionBound When using GSS mechanisms that require more than one round-trip to complete authentication (like NTLMSSP) it is necessary to bind to the authentication to the connection in order to keep the state between round-trips. With this option enable incomplete context are store in the connection and retrieved on the next request for continuation. #### Example GssapiConnectionBound On ### GssapiSignalPersistentAuth For clients that make use of Persistent-Auth header, send the header according to GssapiConnectionBound setting. #### Example GssapiSignalPersistentAuth On ### GssapiUseSessions In order to avoid constant and costly re-authentication attempts for every request, mod_auth_gssapi offers a cookie based session method to maintain authentication across multiple requests. GSSAPI uses the mod_sessions module to handle cookies so that module needs to be activated and configured. GSSAPI uses a secured (encrypted + MAC-ed) payload to maintain state in the session cookie. The session cookie lifetime depends on the lifetime of the GSSAPI session established at authentication. **NOTE**: It is important to correctly set the SessionCookieName option. See the [mod_sessions](http://httpd.apache.org/docs/current/mod/mod_session.html) documentation for more information. #### Example GssapiUseSessions On Session On SessionCookieName gssapi_session path=/private;httponly;secure; ### GssapiSessionKey When GssapiUseSessions is enabled a key use to encrypt and MAC the session data will be automatically generated at startup, this means session data will become unreadable if the server is restarted or multiple servers are used and the client is load balanced from one to another. To obviate this problem the admin can choose to install a permanent key in the configuration so that session data remain accessible after a restart or by multiple servers sharing the same key. The key must be a base64 encoded raw key of 32 bytes of length. #### Example GssapiSessionKey key:VGhpcyBpcyBhIDMyIGJ5dGUgbG9uZyBzZWNyZXQhISE= ### GssapiCredStore The GssapiCredStore option allows to specify multiple credential related options like keytab location, client_keytab location, ccache location etc. #### Example GssapiCredStore keytab:/etc/httpd.keytab GssapiCredStore ccache:FILE:/var/run/httpd/krb5ccache ### GssapiDelegCcacheDir If delegation of credentials is desired credentials can be exported in a private directory accessible by the Apache process. The delegated credentials will be stored in a file named after the client principal and the subprocess environment variable KRB5CCNAME will be set to point to that file. #### Example GssapiDelegCcacheDir /var/run/httpd/clientcaches A user foo@EXAMPLE.COM delegating its credentials would cause the server to create a ccache file named /var/run/httpd/clientcaches/foo@EXAMPLE.COM ### GssapiUseS4U2Proxy Enables the use of the s4u2Proxy Kerberos extension also known as [constrained delegation](https://ssimo.org/blog/id_011.html) This option allows an application running within Apache to operate on behalf of the user against other servers by using the provided ticket (subject to KDC authorization). This options requires GssapiDelegCcacheDir to be set. The ccache will be populated with the user's provided ticket which is later used as evidence ticket by the application. **Note:** This flag has no effect when Basic-Auth is used since user's credentials are delegated anyway when GssapiDelegCcacheDir is set. #### Example GssapiUseS4U2Proxy On GssapiCredStore keytab:/etc/httpd.keytab GssapiCredStore client_keytab:/etc/httpd.keytab GssapiCredStore ccache:FILE:/var/run/httpd/krb5ccache GssapiDelegCcacheDir /var/run/httpd/clientcaches **NOTE:** The client keytab is necessary to allow GSSAPI to initiate via keytab on its own. If not present an external mechanism needs to kinit with the keytab and store a ccache in the configured ccache file. ### GssapiBasicAuth Allows the use of Basic Auth in conjunction with Negotiate. If the browser fails to use Negotiate it will instead fallback to Basic and the username and password will be used to try to acquire credentials in the module via GSSAPI. If credentials are acquired successfully then they are validated against the server's keytab. - **Enable with:** GssapiBasicAuth On - **Default:** GssapiBasicAuth Off #### Example AuthType GSSAPI AuthName "Login" GssapiBasicAuth On GssapiCredStore keytab:/etc/httpd/http.keytab Require valid-user ### GssapiAllowedMech List of allowed mechanisms. This is useful to restrict the mechanism that can be used when credentials for multiple mechanisms are available. By default no mechanism is set, this means all locally available mechanisms are allowed. The recognized mechanism names are: krb5, iakerb, ntlmssp #### Example GssapiAllowedMech krb5 GssapiAllowedMech ntlmssp ### GssapiBasicAuthMech List of mechanisms against which Basic Auth is attempted. This is useful to restrict the mechanisms that can be used to attempt password auth. By default no mechanism is set, this means all locally available mechanisms are allowed, unless GssapiAllowedMech is set, in which case those are used. GssapiBasicAuthMech always takes precedence over GssapiAllowedMech. The recognized mechanism names are: krb5, iakerb, ntlmssp #### Example GssapiBasicAuthMech krb5 ### GssapiNameAttributes Enables the module to source Name Attributes from the client name (authorization data associated with the established context) and exposes them as environment variables. Value format: ENV_VAR_NAME ATTRIBUTE_NAME This option can be specified multiple times, once for each attribute to expose. The Special value "json" is used to expose all attributes in a json formatted string via the special environment variable GSS_NAME_ATTRS_JSON The environment variable GSS_NAME_ATTR_ERROR is set with the Gssapi returned error string in case the inquire name function fails to retrieve attributes, and with the string "0 attributes found", if no attributes are set. **Note**: These variables are NOT saved in the session data stored in the cookie so they are available only on the first authenticated request when GssapiUseSessions is used. **Note:** It is recommended but not required to use only capital letters and underscores for environment variable names. #### Example GssapiNameAttributes json GssapiNameAttributes RADIUS_NAME urn:ietf:params:gss:radius-attribute_1 ### GssapiNegotiateOnce When this option is enabled the Negotiate header will not be resent if Negotiation has already been attempted but failed. Normally when a client fails to use Negotiate authentication, a HTTP 401 response is returned with a WWW-Authenticate: Negotiate header, implying that the client can retry to use Negotiate with different credentials or a different mechanism. Consider enabling GssapiNegotiateOnce when only one single sign on mechanism is allowed, or when GssapiBasicAuth is enabled. **NOTE:** if the initial Negotiate attempt fails, some browsers will fallback to other Negotiate mechanisms, prompting the user for login credentials and reattempting negotiation. This situation can mislead users - for example if krb5 authentication failed and no other mechanisms are allowed, a user could be prompted for login information even though any login information provided cannot succeed. When this occurs, some browsers will not fall back to a Basic Auth mechanism. Enable GssapiNegotiateOnce to avoid this situation. - **Enable with:** GssapiNegotiateOnce On - **Default:** GssapiNegotiateOnce Off mod_auth_gssapi-1.3.2/README.md000077700000000000000000000000001266122234600170212READMEustar00rootroot00000000000000mod_auth_gssapi-1.3.2/configure.ac000066400000000000000000000056201266122234600171600ustar00rootroot00000000000000AC_PREREQ([2.69]) AC_INIT([mod_auth_gssapi], [1.3.3], [simo@redhat.com]) AC_CONFIG_SRCDIR([src/mod_auth_gssapi.c]) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects tar-pax]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([src/config.h]) # Checks for programs. AC_PROG_CC_STDC AC_PROG_LIBTOOL AC_SUBST(INCLTDL) AC_SUBST(LIBLTDL) AM_CONDITIONAL([HAVE_GCC], [test "$ac_cv_prog_gcc" = yes]) AC_CHECK_HEADERS([stdint.h]) # Checks for typedefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL AC_TYPE_SIZE_T AC_TYPE_UINT32_T # Checks for library functions. AC_CHECK_FUNCS([strcasecmp]) AC_ARG_WITH([apxs], [AC_HELP_STRING([--with-apxs=PATH/NAME], [path to the apxs binary [[apxs]]])], [AC_SUBST(APXS, $with_apxs)], [AC_PATH_PROGS(APXS, [apxs2 apxs])]) AS_IF([test "x${APXS}" != "x" -a -x "${APXS}"], [AC_MSG_NOTICE([apxs found at $APXS]) APXS_LIBEXECDIR=`${APXS} -q LIBEXECDIR` AC_SUBST(APXS_LIBEXECDIR)], [AC_MSG_FAILURE(["apxs not found. Use --with-apxs"])]) AC_ARG_WITH([apr], [AC_HELP_STRING([--with-apr=PATH/NAME], [path to the apr binary [[apr]]])], [AC_SUBST(APR, $with_apr)], [AC_PATH_PROGS(APR, [apr-1-config])]) AS_IF([test "x${APR}" != "x" -a -x "${APR}"], [AC_MSG_NOTICE([apr found at $APR]) APR_CPPFLAGS=`${APR} --cppflags` AC_SUBST(APR_CPPFLAGS) APR_INCLUDES=`${APR} --includes` AC_SUBST(APR_INCLUDES) APR_LDFLAGS=`${APR} --link-libtool --libs` AC_SUBST(APR_LDFLAGS)], [AC_MSG_FAILURE(["apr-1-config not found. Use --with-apr"])]) PKG_CHECK_MODULES([OPENSSL], [openssl]) AC_SUBST([OPENSSL_CFLAGS]) AC_SUBST([OPENSSL_LIBS]) AC_CHECK_HEADERS([gssapi/gssapi.h gssapi/gssapi_ext.h gssapi/gssapi_krb5.h], ,[AC_MSG_ERROR([Could not find GSSAPI headers])]) AC_CHECK_HEADERS([gssapi/gssapi_ntlmssp.h]) AC_PATH_PROG(KRB5_CONFIG, krb5-config, failed) if test x$KRB5_CONFIG = xfailed; then AC_MSG_ERROR([Could not find GSSAPI development libraries]) else GSSAPI_CFLAGS="`$KRB5_CONFIG --cflags gssapi`" GSSAPI_LIBS="`$KRB5_CONFIG --libs gssapi`" fi AC_CHECK_LIB([gssapi_krb5], [gss_accept_sec_context], [], [AC_MSG_ERROR([GSSAPI library check failed])]) AC_CHECK_FUNCS(gss_acquire_cred_from) AC_CHECK_FUNCS(gss_store_cred_into) AC_CHECK_FUNCS(gss_acquire_cred_with_password) AC_CHECK_FUNCS(gss_krb5_ccache_name) AC_SUBST([GSSAPI_CFLAGS]) AC_SUBST([GSSAPI_LIBS]) MAG_CFLAGS="`${APXS} -q CFLAGS` `${APXS} -q EXTRA_CPPFLAGS` `${APR} --cflags` ${GSSAPI_CFLAGS} ${OPENSSL_CFLAGS} -I`${APXS} -q INCLUDEDIR` `${APR} --includes`" MAG_LIBS="`${APR} --libs` ${GSSAPI_LIBS} ${OPENSSL_LIBS}" LIBTOOL="`${APXS} -q LIBTOOL`" MAG_LIBDIR="`${APXS} -q libexecdir`" AC_SUBST([MAG_CFLAGS]) AC_SUBST([MAG_LIBS]) AC_SUBST([LIBTOOL]) AC_SUBST([MAG_LIBDIR]) AC_CONFIG_FILES([Makefile src/Makefile src/asn1c/Makefile]) AC_OUTPUT mod_auth_gssapi-1.3.2/contrib/000077500000000000000000000000001266122234600163275ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/contrib/mod_auth_gssapi.spec000066400000000000000000000042111266122234600223470ustar00rootroot00000000000000Name: mod_auth_gssapi Version: 1.3.2 Release: 1%{?dist} Summary: A GSSAPI Authentication module for Apache Group: System Environment/Daemons License: MIT URL: https://github.com/modauthgssapi/mod_auth_gssapi Source0: https://github.com/modauthgssapi/%{name}/releases/download/v%{version}/%name-%{version}.tar.gz BuildRequires: httpd-devel, krb5-devel, openssl-devel Requires: httpd-mmn = %{_httpd_mmn} Requires: krb5-libs >= 1.11.5 %description The mod_auth_gssapi module is an authentication service that implements the SPNEGO based HTTP Authentication protocol defined in RFC4559. %prep %setup -q %build export APXS=%{_httpd_apxs} %configure make %{?_smp_mflags} %install mkdir -p %{buildroot}%{_httpd_moddir} install -m 755 src/.libs/%{name}.so %{buildroot}%{_httpd_moddir} # Apache configuration for the module echo "LoadModule auth_gssapi_module modules/mod_auth_gssapi.so" > 10-auth_gssapi.conf mkdir -p %{buildroot}%{_httpd_modconfdir} install -m 644 10-auth_gssapi.conf %{buildroot}%{_httpd_modconfdir} %files %doc %defattr(-,root,root) %doc README COPYING %config(noreplace) %{_httpd_modconfdir}/10-auth_gssapi.conf %{_httpd_moddir}/mod_auth_gssapi.so %changelog * Wed Feb 17 2015 Simo Sorce 1.3.2-1 - NEAR Shoemaker launch (1996) release (1.3.2) * Thu Sep 3 2015 Simo Sorce 1.3.1-1 - Viking 2 landing (1976) release (1.3.1) * Sat Jul 4 2015 Simo Sorce 1.3.0-1 - US Independence day release (1.3.0) * Thu Apr 21 2015 Simo Sorce 1.2.0-1 - New minor release 1.2.0 * Thu Apr 2 2015 Simo Sorce 1.1.1-1 - New minor release 1.1.1 * Thu Mar 12 2015 Simo Sorce 1.1.0-1 - New minor release 1.1.0 * Sat Nov 8 2014 Simo Sorce 1.0.4-1 - Patch release 1.0.4 * Sat Oct 11 2014 Simo Sorce 1.0.3-1 - Patch release 1.0.3 * Thu Aug 26 2014 Simo Sorce 1.0.2-1 - Patch release 1.0.2 * Thu Aug 14 2014 Simo Sorce 1.0.1-1 - Patch release 1.0.1 * Mon Aug 4 2014 Simo Sorce 1.0.0-1 - First release mod_auth_gssapi-1.3.2/example/000077500000000000000000000000001266122234600163225ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/example/10-auth_gssapi.conf000066400000000000000000000000711266122234600217140ustar00rootroot00000000000000LoadModule auth_gssapi_module modules/mod_auth_gssapi.so mod_auth_gssapi-1.3.2/src/000077500000000000000000000000001266122234600154565ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/src/Makefile.am000066400000000000000000000013341266122234600175130ustar00rootroot00000000000000AM_CPPFLAGS = -I $(srcdir)/asn1c magdir = $(MAG_LIBDIR) mag_LTLIBRARIES = \ mod_auth_gssapi.la dist_noinst_HEADERS = \ mod_auth_gssapi.h crypto.h sessions.h environ.h mod_auth_gssapi_la_SOURCES = \ mod_auth_gssapi.c crypto.c sessions.c environ.c mod_auth_gssapi_la_CFLAGS = \ $(MAG_CFLAGS) mod_auth_gssapi_la_LIBADD = \ asn1c/libmagasn1.la mod_auth_gssapi_la_LDFLAGS = \ $(MAG_LIBS) \ -avoid-version \ -module \ -export-symbols-regex auth_gssapi_module install-exec-local: if test ! -d ${APXS_LIBEXECDIR}; then mkdir -p ${APXS_LIBEXECDIR}; fi @APXS@ -i -S LIBEXECDIR=${APXS_LIBEXECDIR} mod_auth_gssapi.la clean-local: rm -f mod_auth_gssapi.slo mod_auth_gssapi.la mod_auth_gssapi.lo .libs mod_auth_gssapi-1.3.2/src/asn1c/000077500000000000000000000000001266122234600164635ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/src/asn1c/BIT_STRING.c000066400000000000000000000107401266122234600203350ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* * BIT STRING basic type description. */ static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) }; static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = { sizeof(BIT_STRING_t), offsetof(BIT_STRING_t, _asn_ctx), ASN_OSUBV_BIT }; asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { "BIT STRING", "BIT_STRING", OCTET_STRING_free, /* Implemented in terms of OCTET STRING */ BIT_STRING_print, BIT_STRING_constraint, OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ OCTET_STRING_decode_xer_binary, BIT_STRING_encode_xer, OCTET_STRING_decode_uper, /* Unaligned PER decoder */ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_BIT_STRING_tags, sizeof(asn_DEF_BIT_STRING_tags) / sizeof(asn_DEF_BIT_STRING_tags[0]), asn_DEF_BIT_STRING_tags, /* Same as above */ sizeof(asn_DEF_BIT_STRING_tags) / sizeof(asn_DEF_BIT_STRING_tags[0]), 0, /* No PER visible constraints */ 0, 0, /* No members */ &asn_DEF_BIT_STRING_specs }; /* * BIT STRING generic constraint. */ int BIT_STRING_constraint(asn_TYPE_descriptor_t *td, const void *sptr, asn_app_constraint_failed_f *ctfailcb, void *app_key) { const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; if(st && st->buf) { if((st->size == 0 && st->bits_unused) || st->bits_unused < 0 || st->bits_unused > 7) { _ASN_CTFAIL(app_key, td, sptr, "%s: invalid padding byte (%s:%d)", td->name, __FILE__, __LINE__); return -1; } } else { _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; } return 0; } static char *_bit_pattern[16] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; asn_enc_rval_t BIT_STRING_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) { asn_enc_rval_t er; char scratch[128]; char *p = scratch; char *scend = scratch + (sizeof(scratch) - 10); const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; int xcan = (flags & XER_F_CANONICAL); uint8_t *buf; uint8_t *end; if(!st || !st->buf) _ASN_ENCODE_FAILED; er.encoded = 0; buf = st->buf; end = buf + st->size - 1; /* Last byte is special */ /* * Binary dump */ for(; buf < end; buf++) { int v = *buf; int nline = xcan?0:(((buf - st->buf) % 8) == 0); if(p >= scend || nline) { er.encoded += p - scratch; _ASN_CALLBACK(scratch, p - scratch); p = scratch; if(nline) _i_ASN_TEXT_INDENT(1, ilevel); } memcpy(p + 0, _bit_pattern[v >> 4], 4); memcpy(p + 4, _bit_pattern[v & 0x0f], 4); p += 8; } if(!xcan && ((buf - st->buf) % 8) == 0) _i_ASN_TEXT_INDENT(1, ilevel); er.encoded += p - scratch; _ASN_CALLBACK(scratch, p - scratch); p = scratch; if(buf == end) { int v = *buf; int ubits = st->bits_unused; int i; for(i = 7; i >= ubits; i--) *p++ = (v & (1 << i)) ? 0x31 : 0x30; er.encoded += p - scratch; _ASN_CALLBACK(scratch, p - scratch); } if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); _ASN_ENCODED_OK(er); cb_failed: _ASN_ENCODE_FAILED; } /* * BIT STRING specific contents printer. */ int BIT_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { static const char *h2c = "0123456789ABCDEF"; char scratch[64]; const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; uint8_t *buf; uint8_t *end; char *p = scratch; (void)td; /* Unused argument */ if(!st || !st->buf) return (cb("", 8, app_key) < 0) ? -1 : 0; ilevel++; buf = st->buf; end = buf + st->size; /* * Hexadecimal dump. */ for(; buf < end; buf++) { if((buf - st->buf) % 16 == 0 && (st->size > 16) && buf != st->buf) { _i_INDENT(1); /* Dump the string */ if(cb(scratch, p - scratch, app_key) < 0) return -1; p = scratch; } *p++ = h2c[*buf >> 4]; *p++ = h2c[*buf & 0x0F]; *p++ = 0x20; } if(p > scratch) { p--; /* Eat the tailing space */ if((st->size > 16)) { _i_INDENT(1); } /* Dump the incomplete 16-bytes row */ if(cb(scratch, p - scratch, app_key) < 0) return -1; } return 0; } mod_auth_gssapi-1.3.2/src/asn1c/BIT_STRING.h000066400000000000000000000014701266122234600203420ustar00rootroot00000000000000/*- * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _BIT_STRING_H_ #define _BIT_STRING_H_ #include /* Some help from OCTET STRING */ #ifdef __cplusplus extern "C" { #endif typedef struct BIT_STRING_s { uint8_t *buf; /* BIT STRING body */ int size; /* Size of the above buffer */ int bits_unused;/* Unused trailing bits in the last octet (0..7) */ asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ } BIT_STRING_t; extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; asn_struct_print_f BIT_STRING_print; /* Human-readable output */ asn_constr_check_f BIT_STRING_constraint; xer_type_encoder_f BIT_STRING_encode_xer; #ifdef __cplusplus } #endif #endif /* _BIT_STRING_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/BOOLEAN.c000066400000000000000000000141431266122234600177110ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* * 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: /* "" */ *st = 0; break; case XCT_UNKNOWN_BO: if(xer_check_tag(chunk_buf, chunk_size, "true") != XCT_BOTH) return XPBD_BROKEN_ENCODING; /* "" */ *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("", 7); er.encoded = 7; } else { _ASN_CALLBACK("", 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 = ""; 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); } mod_auth_gssapi-1.3.2/src/asn1c/BOOLEAN.h000066400000000000000000000015731266122234600177210ustar00rootroot00000000000000/*- * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _BOOLEAN_H_ #define _BOOLEAN_H_ #include #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_ */ mod_auth_gssapi-1.3.2/src/asn1c/GSSSessionData.c000066400000000000000000000070711266122234600214260ustar00rootroot00000000000000/* * Generated by asn1c-0.9.27 (http://lionet.info/asn1c) * From ASN.1 module "GssapiSessionModule" * found in "session.asn1" * `asn1c -fskeletons-copy` */ #include "GSSSessionData.h" static asn_TYPE_member_t asn_MBR_GSSSessionData_1[] = { { 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 */ 0, "expiration" }, { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, username), (ASN_TAG_CLASS_CONTEXT | (3 << 2)), +1, /* EXPLICIT tag at current level */ &asn_DEF_OCTET_STRING, 0, /* Defer constraints checking to the member type */ 0, /* PER is not compiled, use -gen-PER */ 0, "username" }, { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, gssname), (ASN_TAG_CLASS_CONTEXT | (4 << 2)), +1, /* EXPLICIT tag at current level */ &asn_DEF_OCTET_STRING, 0, /* Defer constraints checking to the member type */ 0, /* PER is not compiled, use -gen-PER */ 0, "gssname" }, { ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, basichash), (ASN_TAG_CLASS_CONTEXT | (5 << 2)), +1, /* EXPLICIT tag at current level */ &asn_DEF_OCTET_STRING, 0, /* Defer constraints checking to the member type */ 0, /* PER is not compiled, use -gen-PER */ 0, "basichash" }, }; 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 }, /* 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 */ { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 } /* basichash */ }; static asn_SEQUENCE_specifics_t asn_SPC_GSSSessionData_specs_1 = { sizeof(struct GSSSessionData), offsetof(struct GSSSessionData, _asn_ctx), asn_MAP_GSSSessionData_tag2el_1, 6, /* Count of tags in the map */ 0, 0, 0, /* Optional elements (not needed) */ -1, /* Start extensions */ -1 /* Stop extensions */ }; asn_TYPE_descriptor_t asn_DEF_GSSSessionData = { "GSSSessionData", "GSSSessionData", SEQUENCE_free, SEQUENCE_print, SEQUENCE_constraint, SEQUENCE_decode_ber, SEQUENCE_encode_der, SEQUENCE_decode_xer, SEQUENCE_encode_xer, 0, 0, /* No PER support, use "-gen-PER" to enable */ 0, /* Use generic outmost tag fetcher */ asn_DEF_GSSSessionData_tags_1, sizeof(asn_DEF_GSSSessionData_tags_1) /sizeof(asn_DEF_GSSSessionData_tags_1[0]), /* 1 */ asn_DEF_GSSSessionData_tags_1, /* Same as above */ sizeof(asn_DEF_GSSSessionData_tags_1) /sizeof(asn_DEF_GSSSessionData_tags_1[0]), /* 1 */ 0, /* No PER visible constraints */ asn_MBR_GSSSessionData_1, 6, /* Elements count */ &asn_SPC_GSSSessionData_specs_1 /* Additional specs */ }; mod_auth_gssapi-1.3.2/src/asn1c/GSSSessionData.h000066400000000000000000000015771266122234600214400ustar00rootroot00000000000000/* * Generated by asn1c-0.9.27 (http://lionet.info/asn1c) * From ASN.1 module "GssapiSessionModule" * found in "session.asn1" * `asn1c -fskeletons-copy` */ #ifndef _GSSSessionData_H_ #define _GSSSessionData_H_ #include /* Including external dependencies */ #include #include "Uint32.h" #include #include #ifdef __cplusplus extern "C" { #endif /* GSSSessionData */ typedef struct GSSSessionData { BOOLEAN_t established; BOOLEAN_t delegated; Uint32_t expiration; OCTET_STRING_t username; OCTET_STRING_t gssname; OCTET_STRING_t basichash; /* Context for parsing across buffer boundaries */ asn_struct_ctx_t _asn_ctx; } GSSSessionData_t; /* Implementation */ extern asn_TYPE_descriptor_t asn_DEF_GSSSessionData; #ifdef __cplusplus } #endif #endif /* _GSSSessionData_H_ */ #include mod_auth_gssapi-1.3.2/src/asn1c/INTEGER.c000066400000000000000000000612301266122234600177260ustar00rootroot00000000000000/*- * Copyright (c) 2003-2014 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* Encoder and decoder of a primitive type */ #include /* * INTEGER basic type description. */ static ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) }; asn_TYPE_descriptor_t asn_DEF_INTEGER = { "INTEGER", "INTEGER", ASN__PRIMITIVE_TYPE_free, INTEGER_print, asn_generic_no_constraint, ber_decode_primitive, INTEGER_encode_der, INTEGER_decode_xer, INTEGER_encode_xer, #ifdef ASN_DISABLE_PER_SUPPORT 0, 0, #else INTEGER_decode_uper, /* Unaligned PER decoder */ INTEGER_encode_uper, /* Unaligned PER encoder */ #endif /* ASN_DISABLE_PER_SUPPORT */ 0, /* Use generic outmost tag fetcher */ asn_DEF_INTEGER_tags, sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), asn_DEF_INTEGER_tags, /* Same as above */ sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), 0, /* No PER visible constraints */ 0, 0, /* No members */ 0 /* No specifics */ }; /* * Encode INTEGER type using DER. */ asn_enc_rval_t INTEGER_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) { INTEGER_t *st = (INTEGER_t *)sptr; ASN_DEBUG("%s %s as INTEGER (tm=%d)", cb?"Encoding":"Estimating", td->name, tag_mode); /* * Canonicalize integer in the buffer. * (Remove too long sign extension, remove some first 0x00 bytes) */ if(st->buf) { uint8_t *buf = st->buf; uint8_t *end1 = buf + st->size - 1; int shift; /* Compute the number of superfluous leading bytes */ for(; buf < end1; buf++) { /* * If the contents octets of an integer value encoding * consist of more than one octet, then the bits of the * first octet and bit 8 of the second octet: * a) shall not all be ones; and * b) shall not all be zero. */ switch(*buf) { case 0x00: if((buf[1] & 0x80) == 0) continue; break; case 0xff: if((buf[1] & 0x80)) continue; break; } break; } /* Remove leading superfluous bytes from the integer */ shift = buf - st->buf; if(shift) { uint8_t *nb = st->buf; uint8_t *end; st->size -= shift; /* New size, minus bad bytes */ end = nb + st->size; for(; nb < end; nb++, buf++) *nb = *buf; } } /* if(1) */ return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key); } static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop); /* * INTEGER specific human-readable output. */ static ssize_t INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; char scratch[32]; /* Enough for 64-bit integer */ uint8_t *buf = st->buf; uint8_t *buf_end = st->buf + st->size; signed long value; ssize_t wrote = 0; char *p; int ret; if(specs && specs->field_unsigned) ret = asn_INTEGER2ulong(st, (unsigned long *)&value); else ret = asn_INTEGER2long(st, &value); /* Simple case: the integer size is small */ if(ret == 0) { const asn_INTEGER_enum_map_t *el; size_t scrsize; char *scr; el = (value >= 0 || !specs || !specs->field_unsigned) ? INTEGER_map_value2enum(specs, value) : 0; if(el) { scrsize = el->enum_len + 32; scr = (char *)alloca(scrsize); if(plainOrXER == 0) ret = snprintf(scr, scrsize, "%ld (%s)", value, el->enum_name); else ret = snprintf(scr, scrsize, "<%s/>", el->enum_name); } else if(plainOrXER && specs && specs->strict_enumeration) { ASN_DEBUG("ASN.1 forbids dealing with " "unknown value of ENUMERATED type"); errno = EPERM; return -1; } else { scrsize = sizeof(scratch); scr = scratch; ret = snprintf(scr, scrsize, (specs && specs->field_unsigned) ?"%lu":"%ld", value); } assert(ret > 0 && (size_t)ret < scrsize); return (cb(scr, ret, app_key) < 0) ? -1 : ret; } else if(plainOrXER && specs && specs->strict_enumeration) { /* * Here and earlier, we cannot encode the ENUMERATED values * if there is no corresponding identifier. */ ASN_DEBUG("ASN.1 forbids dealing with " "unknown value of ENUMERATED type"); errno = EPERM; return -1; } /* Output in the long xx:yy:zz... format */ /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ for(p = scratch; buf < buf_end; buf++) { static const char *h2c = "0123456789ABCDEF"; if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { /* Flush buffer */ if(cb(scratch, p - scratch, app_key) < 0) return -1; wrote += p - scratch; p = scratch; } *p++ = h2c[*buf >> 4]; *p++ = h2c[*buf & 0x0F]; *p++ = 0x3a; /* ":" */ } if(p != scratch) p--; /* Remove the last ":" */ wrote += p - scratch; return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote; } /* * INTEGER specific human-readable output. */ int INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { const INTEGER_t *st = (const INTEGER_t *)sptr; ssize_t ret; (void)td; (void)ilevel; if(!st || !st->buf) ret = cb("", 8, app_key); else ret = INTEGER__dump(td, st, cb, app_key, 0); return (ret < 0) ? -1 : 0; } struct e2v_key { const char *start; const char *stop; asn_INTEGER_enum_map_t *vemap; unsigned int *evmap; }; static int INTEGER__compar_enum2value(const void *kp, const void *am) { const struct e2v_key *key = (const struct e2v_key *)kp; const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; const char *ptr, *end, *name; /* Remap the element (sort by different criterion) */ el = key->vemap + key->evmap[el - key->vemap]; /* Compare strings */ for(ptr = key->start, end = key->stop, name = el->enum_name; ptr < end; ptr++, name++) { if(*ptr != *name) return *(const unsigned char *)ptr - *(const unsigned char *)name; } return name[0] ? -1 : 0; } static const asn_INTEGER_enum_map_t * INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) { asn_INTEGER_enum_map_t *el_found; int count = specs ? specs->map_count : 0; struct e2v_key key; const char *lp; if(!count) return NULL; /* Guaranteed: assert(lstart < lstop); */ /* Figure out the tag name */ for(lstart++, lp = lstart; lp < lstop; lp++) { switch(*lp) { case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */ case 0x2f: /* '/' */ case 0x3e: /* '>' */ break; default: continue; } break; } if(lp == lstop) return NULL; /* No tag found */ lstop = lp; key.start = lstart; key.stop = lstop; key.vemap = specs->value2enum; key.evmap = specs->enum2value; el_found = (asn_INTEGER_enum_map_t *)bsearch(&key, specs->value2enum, count, sizeof(specs->value2enum[0]), INTEGER__compar_enum2value); if(el_found) { /* Remap enum2value into value2enum */ el_found = key.vemap + key.evmap[el_found - key.vemap]; } return el_found; } static int INTEGER__compar_value2enum(const void *kp, const void *am) { long a = *(const long *)kp; const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; long b = el->nat_value; if(a < b) return -1; else if(a == b) return 0; else return 1; } const asn_INTEGER_enum_map_t * INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) { int count = specs ? specs->map_count : 0; if(!count) return 0; return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum, count, sizeof(specs->value2enum[0]), INTEGER__compar_value2enum); } static int INTEGER_st_prealloc(INTEGER_t *st, int min_size) { void *p = MALLOC(min_size + 1); if(p) { void *b = st->buf; st->size = 0; st->buf = p; FREEMEM(b); return 0; } else { return -1; } } /* * Decode the chunk of XML text encoding INTEGER. */ static enum xer_pbd_rval INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { INTEGER_t *st = (INTEGER_t *)sptr; long dec_value; long hex_value = 0; const char *lp; const char *lstart = (const char *)chunk_buf; const char *lstop = lstart + chunk_size; enum { ST_LEADSPACE, ST_SKIPSPHEX, ST_WAITDIGITS, ST_DIGITS, ST_DIGITS_TRAILSPACE, ST_HEXDIGIT1, ST_HEXDIGIT2, ST_HEXDIGITS_TRAILSPACE, ST_HEXCOLON, ST_END_ENUM, ST_UNEXPECTED } state = ST_LEADSPACE; const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */ const char *dec_value_end = 0; if(chunk_size) ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x", (long)chunk_size, *lstart, lstop[-1]); if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) return XPBD_SYSTEM_FAILURE; /* * We may have received a tag here. It will be processed inline. * Use strtoul()-like code and serialize the result. */ for(lp = lstart; lp < lstop; lp++) { int lv = *lp; switch(lv) { case 0x09: case 0x0a: case 0x0d: case 0x20: switch(state) { case ST_LEADSPACE: case ST_DIGITS_TRAILSPACE: case ST_HEXDIGITS_TRAILSPACE: case ST_SKIPSPHEX: continue; case ST_DIGITS: dec_value_end = lp; state = ST_DIGITS_TRAILSPACE; continue; case ST_HEXCOLON: state = ST_HEXDIGITS_TRAILSPACE; continue; default: break; } break; case 0x2d: /* '-' */ if(state == ST_LEADSPACE) { dec_value = 0; dec_value_start = lp; state = ST_WAITDIGITS; continue; } break; case 0x2b: /* '+' */ if(state == ST_LEADSPACE) { dec_value = 0; dec_value_start = lp; state = ST_WAITDIGITS; continue; } break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: switch(state) { case ST_DIGITS: continue; case ST_SKIPSPHEX: /* Fall through */ case ST_HEXDIGIT1: hex_value = (lv - 0x30) << 4; state = ST_HEXDIGIT2; continue; case ST_HEXDIGIT2: hex_value += (lv - 0x30); state = ST_HEXCOLON; st->buf[st->size++] = (uint8_t)hex_value; continue; case ST_HEXCOLON: return XPBD_BROKEN_ENCODING; case ST_LEADSPACE: dec_value = 0; dec_value_start = lp; /* FALL THROUGH */ case ST_WAITDIGITS: state = ST_DIGITS; continue; default: break; } break; case 0x3c: /* '<', start of XML encoded enumeration */ if(state == ST_LEADSPACE) { const asn_INTEGER_enum_map_t *el; el = INTEGER_map_enum2value( (asn_INTEGER_specifics_t *) td->specifics, lstart, lstop); if(el) { ASN_DEBUG("Found \"%s\" => %ld", el->enum_name, el->nat_value); dec_value = el->nat_value; state = ST_END_ENUM; lp = lstop - 1; continue; } ASN_DEBUG("Unknown identifier for INTEGER"); } return XPBD_BROKEN_ENCODING; case 0x3a: /* ':' */ if(state == ST_HEXCOLON) { /* This colon is expected */ state = ST_HEXDIGIT1; continue; } else if(state == ST_DIGITS) { /* The colon here means that we have * decoded the first two hexadecimal * places as a decimal value. * Switch decoding mode. */ ASN_DEBUG("INTEGER re-evaluate as hex form"); state = ST_SKIPSPHEX; dec_value_start = 0; lp = lstart - 1; continue; } else { ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart)); break; } /* [A-Fa-f] */ case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46: case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: switch(state) { case ST_SKIPSPHEX: case ST_LEADSPACE: /* Fall through */ case ST_HEXDIGIT1: hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61); hex_value += 10; hex_value <<= 4; state = ST_HEXDIGIT2; continue; case ST_HEXDIGIT2: hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61); hex_value += 10; st->buf[st->size++] = (uint8_t)hex_value; state = ST_HEXCOLON; continue; case ST_DIGITS: ASN_DEBUG("INTEGER re-evaluate as hex form"); state = ST_SKIPSPHEX; dec_value_start = 0; lp = lstart - 1; continue; default: break; } break; } /* Found extra non-numeric stuff */ ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld", lv, (long)(lp - lstart)); state = ST_UNEXPECTED; break; } switch(state) { case ST_END_ENUM: /* Got a complete and valid enumeration encoded as a tag. */ break; case ST_DIGITS: dec_value_end = lstop; /* FALL THROUGH */ case ST_DIGITS_TRAILSPACE: /* The last symbol encountered was a digit. */ switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) { case ASN_STRTOL_OK: break; case ASN_STRTOL_ERROR_RANGE: return XPBD_DECODER_LIMIT; case ASN_STRTOL_ERROR_INVAL: case ASN_STRTOL_EXPECT_MORE: case ASN_STRTOL_EXTRA_DATA: return XPBD_BROKEN_ENCODING; } break; case ST_HEXCOLON: case ST_HEXDIGITS_TRAILSPACE: st->buf[st->size] = 0; /* Just in case termination */ return XPBD_BODY_CONSUMED; case ST_HEXDIGIT1: case ST_HEXDIGIT2: case ST_SKIPSPHEX: return XPBD_BROKEN_ENCODING; case ST_LEADSPACE: /* Content not found */ return XPBD_NOT_BODY_IGNORE; case ST_WAITDIGITS: case ST_UNEXPECTED: ASN_DEBUG("INTEGER: No useful digits (state %d)", state); return XPBD_BROKEN_ENCODING; /* No digits */ } /* * Convert the result of parsing of enumeration or a straight * decimal value into a BER representation. */ if(asn_long2INTEGER(st, dec_value)) return XPBD_SYSTEM_FAILURE; return XPBD_BODY_CONSUMED; } asn_dec_rval_t INTEGER_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(INTEGER_t), opt_mname, buf_ptr, size, INTEGER__xer_body_decode); } asn_enc_rval_t INTEGER_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 INTEGER_t *st = (const INTEGER_t *)sptr; asn_enc_rval_t er; (void)ilevel; (void)flags; if(!st || !st->buf) _ASN_ENCODE_FAILED; er.encoded = INTEGER__dump(td, st, cb, app_key, 1); if(er.encoded < 0) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } #ifndef ASN_DISABLE_PER_SUPPORT asn_dec_rval_t INTEGER_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_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval = { RC_OK, 0 }; INTEGER_t *st = (INTEGER_t *)*sptr; asn_per_constraint_t *ct; int repeat; (void)opt_codec_ctx; if(!st) { st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); if(!st) _ASN_DECODE_FAILED; } if(!constraints) constraints = td->per_constraints; ct = constraints ? &constraints->value : 0; if(ct && ct->flags & APC_EXTENSIBLE) { int inext = per_get_few_bits(pd, 1); if(inext < 0) _ASN_DECODE_STARVED; if(inext) ct = 0; } FREEMEM(st->buf); st->buf = 0; st->size = 0; if(ct) { if(ct->flags & APC_SEMI_CONSTRAINED) { st->buf = (uint8_t *)CALLOC(1, 2); if(!st->buf) _ASN_DECODE_FAILED; st->size = 1; } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { size_t size = (ct->range_bits + 7) >> 3; st->buf = (uint8_t *)MALLOC(1 + size + 1); if(!st->buf) _ASN_DECODE_FAILED; st->size = size; } } /* X.691-2008/11, #13.2.2, constrained whole number */ if(ct && ct->flags != APC_UNCONSTRAINED) { /* #11.5.6 */ ASN_DEBUG("Integer with range %d bits", ct->range_bits); if(ct->range_bits >= 0) { if((size_t)ct->range_bits > 8 * sizeof(unsigned long)) _ASN_DECODE_FAILED; if(specs && specs->field_unsigned) { unsigned long uvalue; if(uper_get_constrained_whole_number(pd, &uvalue, ct->range_bits)) _ASN_DECODE_STARVED; ASN_DEBUG("Got value %lu + low %ld", uvalue, ct->lower_bound); uvalue += ct->lower_bound; if(asn_ulong2INTEGER(st, uvalue)) _ASN_DECODE_FAILED; } else { unsigned long svalue; if(uper_get_constrained_whole_number(pd, &svalue, ct->range_bits)) _ASN_DECODE_STARVED; ASN_DEBUG("Got value %ld + low %ld", svalue, ct->lower_bound); svalue += ct->lower_bound; if(asn_long2INTEGER(st, svalue)) _ASN_DECODE_FAILED; } return rval; } } else { ASN_DEBUG("Decoding unconstrained integer %s", td->name); } /* X.691, #12.2.3, #12.2.4 */ do { ssize_t len; void *p; int ret; /* Get the PER length */ len = uper_get_length(pd, -1, &repeat); if(len < 0) _ASN_DECODE_STARVED; p = REALLOC(st->buf, st->size + len + 1); if(!p) _ASN_DECODE_FAILED; st->buf = (uint8_t *)p; ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); if(ret < 0) _ASN_DECODE_STARVED; st->size += len; } while(repeat); st->buf[st->size] = 0; /* JIC */ /* #12.2.3 */ if(ct && ct->lower_bound) { /* * TODO: replace by in-place arithmetics. */ long value; if(asn_INTEGER2long(st, &value)) _ASN_DECODE_FAILED; if(asn_long2INTEGER(st, value + ct->lower_bound)) _ASN_DECODE_FAILED; } return rval; } asn_enc_rval_t INTEGER_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_enc_rval_t er; INTEGER_t *st = (INTEGER_t *)sptr; const uint8_t *buf; const uint8_t *end; asn_per_constraint_t *ct; long value = 0; if(!st || st->size == 0) _ASN_ENCODE_FAILED; if(!constraints) constraints = td->per_constraints; ct = constraints ? &constraints->value : 0; er.encoded = 0; if(ct) { int inext = 0; if(specs && specs->field_unsigned) { unsigned long uval; if(asn_INTEGER2ulong(st, &uval)) _ASN_ENCODE_FAILED; /* Check proper range */ if(ct->flags & APC_SEMI_CONSTRAINED) { if(uval < (unsigned long)ct->lower_bound) inext = 1; } else if(ct->range_bits >= 0) { if(uval < (unsigned long)ct->lower_bound || uval > (unsigned long)ct->upper_bound) inext = 1; } ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s", uval, st->buf[0], st->size, ct->lower_bound, ct->upper_bound, inext ? "ext" : "fix"); value = uval; } else { if(asn_INTEGER2long(st, &value)) _ASN_ENCODE_FAILED; /* Check proper range */ if(ct->flags & APC_SEMI_CONSTRAINED) { if(value < ct->lower_bound) inext = 1; } else if(ct->range_bits >= 0) { if(value < ct->lower_bound || value > ct->upper_bound) inext = 1; } ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", value, st->buf[0], st->size, ct->lower_bound, ct->upper_bound, inext ? "ext" : "fix"); } if(ct->flags & APC_EXTENSIBLE) { if(per_put_few_bits(po, inext, 1)) _ASN_ENCODE_FAILED; if(inext) ct = 0; } else if(inext) { _ASN_ENCODE_FAILED; } } /* X.691-11/2008, #13.2.2, test if constrained whole number */ if(ct && ct->range_bits >= 0) { /* #11.5.6 -> #11.3 */ ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits", value, value - ct->lower_bound, ct->range_bits); unsigned long v = value - ct->lower_bound; if(uper_put_constrained_whole_number_u(po, v, ct->range_bits)) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } if(ct && ct->lower_bound) { ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); /* TODO: adjust lower bound */ _ASN_ENCODE_FAILED; } for(buf = st->buf, end = st->buf + st->size; buf < end;) { ssize_t mayEncode = uper_put_length(po, end - buf); if(mayEncode < 0) _ASN_ENCODE_FAILED; if(per_put_many_bits(po, buf, 8 * mayEncode)) _ASN_ENCODE_FAILED; buf += mayEncode; } _ASN_ENCODED_OK(er); } #endif /* ASN_DISABLE_PER_SUPPORT */ int asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { uint8_t *b, *end; size_t size; long l; /* Sanity checking */ if(!iptr || !iptr->buf || !lptr) { errno = EINVAL; return -1; } /* Cache the begin/end of the buffer */ b = iptr->buf; /* Start of the INTEGER buffer */ size = iptr->size; end = b + size; /* Where to stop */ if(size > sizeof(long)) { uint8_t *end1 = end - 1; /* * Slightly more advanced processing, * able to >sizeof(long) bytes, * when the actual value is small * (0x0000000000abcdef would yield a fine 0x00abcdef) */ /* Skip out the insignificant leading bytes */ for(; b < end1; b++) { switch(*b) { case 0x00: if((b[1] & 0x80) == 0) continue; break; case 0xff: if((b[1] & 0x80) != 0) continue; break; } break; } size = end - b; if(size > sizeof(long)) { /* Still cannot fit the long */ errno = ERANGE; return -1; } } /* Shortcut processing of a corner case */ if(end == b) { *lptr = 0; return 0; } /* Perform the sign initialization */ /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */ if((*b >> 7)) l = -1; else l = 0; /* Conversion engine */ for(; b < end; b++) l = (l << 8) | *b; *lptr = l; return 0; } int asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) { uint8_t *b, *end; unsigned long l; size_t size; if(!iptr || !iptr->buf || !lptr) { errno = EINVAL; return -1; } b = iptr->buf; size = iptr->size; end = b + size; /* If all extra leading bytes are zeroes, ignore them */ for(; size > sizeof(unsigned long); b++, size--) { if(*b) { /* Value won't fit unsigned long */ errno = ERANGE; return -1; } } /* Conversion engine */ for(l = 0; b < end; b++) l = (l << 8) | *b; *lptr = l; return 0; } int asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) { uint8_t *buf; uint8_t *end; uint8_t *b; int shr; if(value <= LONG_MAX) return asn_long2INTEGER(st, value); buf = (uint8_t *)MALLOC(1 + sizeof(value)); if(!buf) return -1; end = buf + (sizeof(value) + 1); buf[0] = 0; for(b = buf + 1, shr = (sizeof(long)-1)*8; b < end; shr -= 8, b++) *b = (uint8_t)(value >> shr); if(st->buf) FREEMEM(st->buf); st->buf = buf; st->size = 1 + sizeof(value); return 0; } int asn_long2INTEGER(INTEGER_t *st, long value) { uint8_t *buf, *bp; uint8_t *p; uint8_t *pstart; uint8_t *pend1; int littleEndian = 1; /* Run-time detection */ int add; if(!st) { errno = EINVAL; return -1; } buf = (uint8_t *)MALLOC(sizeof(value)); if(!buf) return -1; if(*(char *)&littleEndian) { pstart = (uint8_t *)&value + sizeof(value) - 1; pend1 = (uint8_t *)&value; add = -1; } else { pstart = (uint8_t *)&value; pend1 = pstart + sizeof(value) - 1; add = 1; } /* * If the contents octet consists of more than one octet, * then bits of the first octet and bit 8 of the second octet: * a) shall not all be ones; and * b) shall not all be zero. */ for(p = pstart; p != pend1; p += add) { switch(*p) { case 0x00: if((*(p+add) & 0x80) == 0) continue; break; case 0xff: if((*(p+add) & 0x80)) continue; break; } break; } /* Copy the integer body */ for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add) *bp++ = *p; if(st->buf) FREEMEM(st->buf); st->buf = buf; st->size = bp - buf; return 0; } /* * This function is going to be DEPRECATED soon. */ enum asn_strtol_result_e asn_strtol(const char *str, const char *end, long *lp) { const char *endp = end; switch(asn_strtol_lim(str, &endp, lp)) { case ASN_STRTOL_ERROR_RANGE: return ASN_STRTOL_ERROR_RANGE; case ASN_STRTOL_ERROR_INVAL: return ASN_STRTOL_ERROR_INVAL; case ASN_STRTOL_EXPECT_MORE: return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ case ASN_STRTOL_OK: return ASN_STRTOL_OK; case ASN_STRTOL_EXTRA_DATA: return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ } return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ } /* * Parse the number in the given string until the given *end position, * returning the position after the last parsed character back using the * same (*end) pointer. * WARNING: This behavior is different from the standard strtol(3). */ enum asn_strtol_result_e asn_strtol_lim(const char *str, const char **end, long *lp) { int sign = 1; long l; const long upper_boundary = LONG_MAX / 10; long last_digit_max = LONG_MAX % 10; if(str >= *end) return ASN_STRTOL_ERROR_INVAL; switch(*str) { case '-': last_digit_max++; sign = -1; case '+': str++; if(str >= *end) { *end = str; return ASN_STRTOL_EXPECT_MORE; } } for(l = 0; str < (*end); str++) { switch(*str) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { int d = *str - '0'; if(l < upper_boundary) { l = l * 10 + d; } else if(l == upper_boundary) { if(d <= last_digit_max) { if(sign > 0) { l = l * 10 + d; } else { sign = 1; l = -l * 10 - d; } } else { *end = str; return ASN_STRTOL_ERROR_RANGE; } } else { *end = str; return ASN_STRTOL_ERROR_RANGE; } } continue; default: *end = str; *lp = sign * l; return ASN_STRTOL_EXTRA_DATA; } } *end = str; *lp = sign * l; return ASN_STRTOL_OK; } mod_auth_gssapi-1.3.2/src/asn1c/INTEGER.h000066400000000000000000000056131266122234600177360ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _INTEGER_H_ #define _INTEGER_H_ #include #include #ifdef __cplusplus extern "C" { #endif typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; extern asn_TYPE_descriptor_t asn_DEF_INTEGER; /* Map with to integer value association */ typedef struct asn_INTEGER_enum_map_s { long nat_value; /* associated native integer value */ size_t enum_len; /* strlen("tag") */ const char *enum_name; /* "tag" */ } asn_INTEGER_enum_map_t; /* This type describes an enumeration for INTEGER and ENUMERATED types */ typedef struct asn_INTEGER_specifics_s { asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ unsigned int *enum2value; /* "tag" => N; sorted by tag */ int map_count; /* Elements in either map */ int extension; /* This map is extensible */ int strict_enumeration; /* Enumeration set is fixed */ int field_width; /* Size of native integer */ int field_unsigned; /* Signed=0, unsigned=1 */ } asn_INTEGER_specifics_t; asn_struct_print_f INTEGER_print; ber_type_decoder_f INTEGER_decode_ber; der_type_encoder_f INTEGER_encode_der; xer_type_decoder_f INTEGER_decode_xer; xer_type_encoder_f INTEGER_encode_xer; per_type_decoder_f INTEGER_decode_uper; per_type_encoder_f INTEGER_encode_uper; /*********************************** * Some handy conversion routines. * ***********************************/ /* * Returns 0 if it was possible to convert, -1 otherwise. * -1/EINVAL: Mandatory argument missing * -1/ERANGE: Value encoded is out of range for long representation * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). */ int asn_INTEGER2long(const INTEGER_t *i, long *l); int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); int asn_long2INTEGER(INTEGER_t *i, long l); int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); /* A a reified version of strtol(3) with nicer error reporting. */ enum asn_strtol_result_e { ASN_STRTOL_ERROR_RANGE = -3, /* Input outside of numeric range for long type */ ASN_STRTOL_ERROR_INVAL = -2, /* Invalid data encountered (e.g., "+-") */ ASN_STRTOL_EXPECT_MORE = -1, /* More data expected (e.g. "+") */ ASN_STRTOL_OK = 0, /* Conversion succeded, number ends at (*end) */ ASN_STRTOL_EXTRA_DATA = 1, /* Conversion succeded, but the string has extra stuff */ }; enum asn_strtol_result_e asn_strtol_lim(const char *str, const char **end, long *l); /* The asn_strtol is going to be DEPRECATED soon */ enum asn_strtol_result_e asn_strtol(const char *str, const char *end, long *l); /* * Convert the integer value into the corresponding enumeration map entry. */ const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); #ifdef __cplusplus } #endif #endif /* _INTEGER_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/Makefile.am000066400000000000000000000022761266122234600205260ustar00rootroot00000000000000NULL = ASN1C_SOURCES = \ asn_codecs_prim.c \ ber_decoder.c \ ber_tlv_length.c \ ber_tlv_tag.c \ BIT_STRING.c \ BOOLEAN.c \ constraints.c \ constr_SEQUENCE.c \ constr_TYPE.c \ der_encoder.c \ INTEGER.c \ NativeEnumerated.c \ NativeInteger.c \ OCTET_STRING.c \ per_decoder.c \ per_encoder.c \ per_opentype.c \ per_support.c \ xer_decoder.c \ xer_encoder.c \ xer_support.c \ asn_application.h \ asn_codecs.h \ asn_codecs_prim.h \ asn_internal.h \ asn_system.h \ ber_decoder.h \ ber_tlv_length.h \ ber_tlv_tag.h \ BIT_STRING.h \ BOOLEAN.h \ constraints.h \ constr_SEQUENCE.h \ constr_TYPE.h \ der_encoder.h \ INTEGER.h \ NativeEnumerated.h \ NativeInteger.h \ OCTET_STRING.h \ per_decoder.h \ per_encoder.h \ per_opentype.h \ per_support.h \ xer_decoder.h \ xer_encoder.h \ xer_support.h \ $(NULL) ASN1Cdir = . MAGASN1_SOURCES = \ GSSSessionData.c \ Uint32.c \ GSSSessionData.h \ Uint32.h \ $(NULL) MAGASN1dir = . noinst_LTLIBRARIES = libmagasn1.la libmagasn1_la_SOURCES = $(ASN1C_SOURCES) $(MAGASN1_SOURCES) regenerate: asn1c -fskeletons-copy -fnative-types session.asn1 rm -f converter-sample.c Makefile.am.sample mod_auth_gssapi-1.3.2/src/asn1c/NativeEnumerated.c000066400000000000000000000134261266122234600220750ustar00rootroot00000000000000/*- * Copyright (c) 2004, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * Read the NativeInteger.h for the explanation wrt. differences between * INTEGER and NativeInteger. * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this * implementation deals with the standard (machine-specific) representation * of them instead of using the platform-independent buffer. */ #include #include /* * NativeEnumerated basic type description. */ static ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (10 << 2)) }; asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { "ENUMERATED", /* The ASN.1 type is still ENUMERATED */ "ENUMERATED", NativeInteger_free, NativeInteger_print, asn_generic_no_constraint, NativeInteger_decode_ber, NativeInteger_encode_der, NativeInteger_decode_xer, NativeEnumerated_encode_xer, NativeEnumerated_decode_uper, NativeEnumerated_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeEnumerated_tags, sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), asn_DEF_NativeEnumerated_tags, /* Same as above */ sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), 0, /* No PER visible constraints */ 0, 0, /* No members */ 0 /* No specifics */ }; asn_enc_rval_t NativeEnumerated_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) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_enc_rval_t er; const long *native = (const long *)sptr; const asn_INTEGER_enum_map_t *el; (void)ilevel; (void)flags; if(!native) _ASN_ENCODE_FAILED; el = INTEGER_map_value2enum(specs, *native); if(el) { size_t srcsize = el->enum_len + 5; char *src = (char *)alloca(srcsize); er.encoded = snprintf(src, srcsize, "<%s/>", el->enum_name); assert(er.encoded > 0 && (size_t)er.encoded < srcsize); if(cb(src, er.encoded, app_key) < 0) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } else { ASN_DEBUG("ASN.1 forbids dealing with " "unknown value of ENUMERATED type"); _ASN_ENCODE_FAILED; } } asn_dec_rval_t NativeEnumerated_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_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval = { RC_OK, 0 }; long *native = (long *)*sptr; asn_per_constraint_t *ct; long value; (void)opt_codec_ctx; if(constraints) ct = &constraints->value; else if(td->per_constraints) ct = &td->per_constraints->value; else _ASN_DECODE_FAILED; /* Mandatory! */ if(!specs) _ASN_DECODE_FAILED; if(!native) { native = (long *)(*sptr = CALLOC(1, sizeof(*native))); if(!native) _ASN_DECODE_FAILED; } ASN_DEBUG("Decoding %s as NativeEnumerated", td->name); if(ct->flags & APC_EXTENSIBLE) { int inext = per_get_few_bits(pd, 1); if(inext < 0) _ASN_DECODE_STARVED; if(inext) ct = 0; } if(ct && ct->range_bits >= 0) { value = per_get_few_bits(pd, ct->range_bits); if(value < 0) _ASN_DECODE_STARVED; if(value >= (specs->extension ? specs->extension - 1 : specs->map_count)) _ASN_DECODE_FAILED; } else { if(!specs->extension) _ASN_DECODE_FAILED; /* * X.691, #10.6: normally small non-negative whole number; */ value = uper_get_nsnnwn(pd); if(value < 0) _ASN_DECODE_STARVED; value += specs->extension - 1; if(value >= specs->map_count) _ASN_DECODE_FAILED; } *native = specs->value2enum[value].nat_value; ASN_DEBUG("Decoded %s = %ld", td->name, *native); return rval; } static int NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { const asn_INTEGER_enum_map_t *a = ap; const asn_INTEGER_enum_map_t *b = bp; if(a->nat_value == b->nat_value) return 0; if(a->nat_value < b->nat_value) return -1; return 1; } asn_enc_rval_t NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; asn_enc_rval_t er; long native, value; asn_per_constraint_t *ct; int inext = 0; asn_INTEGER_enum_map_t key; asn_INTEGER_enum_map_t *kf; if(!sptr) _ASN_ENCODE_FAILED; if(!specs) _ASN_ENCODE_FAILED; if(constraints) ct = &constraints->value; else if(td->per_constraints) ct = &td->per_constraints->value; else _ASN_ENCODE_FAILED; /* Mandatory! */ ASN_DEBUG("Encoding %s as NativeEnumerated", td->name); er.encoded = 0; native = *(long *)sptr; if(native < 0) _ASN_ENCODE_FAILED; key.nat_value = native; kf = bsearch(&key, specs->value2enum, specs->map_count, sizeof(key), NativeEnumerated__compar_value2enum); if(!kf) { ASN_DEBUG("No element corresponds to %ld", native); _ASN_ENCODE_FAILED; } value = kf - specs->value2enum; if(ct->range_bits >= 0) { int cmpWith = specs->extension ? specs->extension - 1 : specs->map_count; if(value >= cmpWith) inext = 1; } if(ct->flags & APC_EXTENSIBLE) { if(per_put_few_bits(po, inext, 1)) _ASN_ENCODE_FAILED; if(inext) ct = 0; } else if(inext) { _ASN_ENCODE_FAILED; } if(ct && ct->range_bits >= 0) { if(per_put_few_bits(po, value, ct->range_bits)) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } if(!specs->extension) _ASN_ENCODE_FAILED; /* * X.691, #10.6: normally small non-negative whole number; */ ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld", value, specs->extension, inext, value - (inext ? (specs->extension - 1) : 0)); if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0))) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } mod_auth_gssapi-1.3.2/src/asn1c/NativeEnumerated.h000066400000000000000000000016011266122234600220720ustar00rootroot00000000000000/*- * Copyright (c) 2004, 2005, 2006 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * This type differs from the standard ENUMERATED in that it is modelled using * the fixed machine type (long, int, short), so it can hold only values of * limited length. There is no type (i.e., NativeEnumerated_t, any integer type * will do). * This type may be used when integer range is limited by subtype constraints. */ #ifndef _NativeEnumerated_H_ #define _NativeEnumerated_H_ #include #ifdef __cplusplus extern "C" { #endif extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; xer_type_encoder_f NativeEnumerated_encode_xer; per_type_decoder_f NativeEnumerated_decode_uper; per_type_encoder_f NativeEnumerated_encode_uper; #ifdef __cplusplus } #endif #endif /* _NativeEnumerated_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/NativeInteger.c000066400000000000000000000211051266122234600213720ustar00rootroot00000000000000/*- * Copyright (c) 2004, 2005, 2006 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * Read the NativeInteger.h for the explanation wrt. differences between * INTEGER and NativeInteger. * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this * implementation deals with the standard (machine-specific) representation * of them instead of using the platform-independent buffer. */ #include #include /* * NativeInteger basic type description. */ static ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) }; asn_TYPE_descriptor_t asn_DEF_NativeInteger = { "INTEGER", /* The ASN.1 type is still INTEGER */ "INTEGER", NativeInteger_free, NativeInteger_print, asn_generic_no_constraint, NativeInteger_decode_ber, NativeInteger_encode_der, NativeInteger_decode_xer, NativeInteger_encode_xer, NativeInteger_decode_uper, /* Unaligned PER decoder */ NativeInteger_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeInteger_tags, sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), asn_DEF_NativeInteger_tags, /* Same as above */ sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), 0, /* No PER visible constraints */ 0, 0, /* No members */ 0 /* No specifics */ }; /* * Decode INTEGER type. */ asn_dec_rval_t NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; long *native = (long *)*nint_ptr; asn_dec_rval_t rval; ber_tlv_len_t length; /* * If the structure is not there, allocate it. */ if(native == NULL) { native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); if(native == NULL) { rval.code = RC_FAIL; rval.consumed = 0; return rval; } } ASN_DEBUG("Decoding %s as INTEGER (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("%s length is %d bytes", td->name, (int)length); /* * Make sure we have this 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; } /* * ASN.1 encoded INTEGER: buf_ptr, length * Fill the native, at the same time checking for overflow. * If overflow occured, return with RC_FAIL. */ { INTEGER_t tmp; union { const void *constbuf; void *nonconstbuf; } unconst_buf; long l; unconst_buf.constbuf = buf_ptr; tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; tmp.size = length; if((specs&&specs->field_unsigned) ? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */ : asn_INTEGER2long(&tmp, &l)) { rval.code = RC_FAIL; rval.consumed = 0; return rval; } *native = l; } rval.code = RC_OK; rval.consumed += length; ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)", (long)rval.consumed, (long)length, td->name, (long)*native); return rval; } /* * Encode the NativeInteger using the standard INTEGER type DER encoder. */ asn_enc_rval_t NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr, int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) { unsigned long native = *(unsigned long *)ptr; /* Disable sign ext. */ asn_enc_rval_t erval; INTEGER_t tmp; #ifdef WORDS_BIGENDIAN /* Opportunistic optimization */ tmp.buf = (uint8_t *)&native; tmp.size = sizeof(native); #else /* Works even if WORDS_BIGENDIAN is not set where should've been */ uint8_t buf[sizeof(native)]; uint8_t *p; /* Prepare a fake INTEGER */ for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8) *p = (uint8_t)native; tmp.buf = buf; tmp.size = sizeof(buf); #endif /* WORDS_BIGENDIAN */ /* Encode fake INTEGER */ erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key); if(erval.encoded == -1) { assert(erval.structure_ptr == &tmp); erval.structure_ptr = ptr; } return erval; } /* * Decode the chunk of XML text encoding INTEGER. */ asn_dec_rval_t NativeInteger_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) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval; INTEGER_t st; void *st_ptr = (void *)&st; long *native = (long *)*sptr; if(!native) { native = (long *)(*sptr = CALLOC(1, sizeof(*native))); if(!native) _ASN_DECODE_FAILED; } memset(&st, 0, sizeof(st)); rval = INTEGER_decode_xer(opt_codec_ctx, td, &st_ptr, opt_mname, buf_ptr, size); if(rval.code == RC_OK) { long l; if((specs&&specs->field_unsigned) ? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */ : asn_INTEGER2long(&st, &l)) { rval.code = RC_FAIL; rval.consumed = 0; } else { *native = l; } } else { /* * Cannot restart from the middle; * there is no place to save state in the native type. * Request a continuation from the very beginning. */ rval.consumed = 0; } ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &st); return rval; } asn_enc_rval_t NativeInteger_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) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; char scratch[32]; /* Enough for 64-bit int */ asn_enc_rval_t er; const long *native = (const long *)sptr; (void)ilevel; (void)flags; if(!native) _ASN_ENCODE_FAILED; er.encoded = snprintf(scratch, sizeof(scratch), (specs && specs->field_unsigned) ? "%lu" : "%ld", *native); if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch) || cb(scratch, er.encoded, app_key) < 0) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } asn_dec_rval_t NativeInteger_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_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval; long *native = (long *)*sptr; INTEGER_t tmpint; void *tmpintptr = &tmpint; (void)opt_codec_ctx; ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name); if(!native) { native = (long *)(*sptr = CALLOC(1, sizeof(*native))); if(!native) _ASN_DECODE_FAILED; } memset(&tmpint, 0, sizeof tmpint); rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints, &tmpintptr, pd); if(rval.code == RC_OK) { if((specs&&specs->field_unsigned) ? asn_INTEGER2ulong(&tmpint, (unsigned long *)native) : asn_INTEGER2long(&tmpint, native)) rval.code = RC_FAIL; else ASN_DEBUG("NativeInteger %s got value %ld", td->name, *native); } ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); return rval; } asn_enc_rval_t NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_enc_rval_t er; long native; INTEGER_t tmpint; if(!sptr) _ASN_ENCODE_FAILED; native = *(long *)sptr; ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); memset(&tmpint, 0, sizeof(tmpint)); if((specs&&specs->field_unsigned) ? asn_ulong2INTEGER(&tmpint, native) : asn_long2INTEGER(&tmpint, native)) _ASN_ENCODE_FAILED; er = INTEGER_encode_uper(td, constraints, &tmpint, po); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); return er; } /* * INTEGER specific human-readable output. */ int NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; const long *native = (const long *)sptr; char scratch[32]; /* Enough for 64-bit int */ int ret; (void)td; /* Unused argument */ (void)ilevel; /* Unused argument */ if(native) { ret = snprintf(scratch, sizeof(scratch), (specs && specs->field_unsigned) ? "%lu" : "%ld", *native); assert(ret > 0 && (size_t)ret < sizeof(scratch)); return (cb(scratch, ret, app_key) < 0) ? -1 : 0; } else { return (cb("", 8, app_key) < 0) ? -1 : 0; } } void NativeInteger_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { if(!td || !ptr) return; ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)", td->name, contents_only, ptr); if(!contents_only) { FREEMEM(ptr); } } mod_auth_gssapi-1.3.2/src/asn1c/NativeInteger.h000066400000000000000000000021041266122234600213750ustar00rootroot00000000000000/*- * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * This type differs from the standard INTEGER in that it is modelled using * the fixed machine type (long, int, short), so it can hold only values of * limited length. There is no type (i.e., NativeInteger_t, any integer type * will do). * This type may be used when integer range is limited by subtype constraints. */ #ifndef _NativeInteger_H_ #define _NativeInteger_H_ #include #include #ifdef __cplusplus extern "C" { #endif extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; asn_struct_free_f NativeInteger_free; asn_struct_print_f NativeInteger_print; ber_type_decoder_f NativeInteger_decode_ber; der_type_encoder_f NativeInteger_encode_der; xer_type_decoder_f NativeInteger_decode_xer; xer_type_encoder_f NativeInteger_encode_xer; per_type_decoder_f NativeInteger_decode_uper; per_type_encoder_f NativeInteger_encode_uper; #ifdef __cplusplus } #endif #endif /* _NativeInteger_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/OCTET_STRING.c000066400000000000000000001332361266122234600206030ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* for .bits_unused member */ #include /* * OCTET STRING basic type description. */ static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) }; static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { sizeof(OCTET_STRING_t), offsetof(OCTET_STRING_t, _asn_ctx), ASN_OSUBV_STR }; static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = { { APC_CONSTRAINED, 8, 8, 0, 255 }, { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, 0, 0 }; asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { "OCTET STRING", /* Canonical name */ "OCTET_STRING", /* XML tag name */ OCTET_STRING_free, OCTET_STRING_print, /* non-ascii stuff, generally */ asn_generic_no_constraint, OCTET_STRING_decode_ber, OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, OCTET_STRING_decode_uper, /* Unaligned PER decoder */ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_OCTET_STRING_tags, sizeof(asn_DEF_OCTET_STRING_tags) / sizeof(asn_DEF_OCTET_STRING_tags[0]), asn_DEF_OCTET_STRING_tags, /* Same as above */ sizeof(asn_DEF_OCTET_STRING_tags) / sizeof(asn_DEF_OCTET_STRING_tags[0]), 0, /* No PER visible constraints */ 0, 0, /* No members */ &asn_DEF_OCTET_STRING_specs }; #undef _CH_PHASE #undef NEXT_PHASE #undef PREV_PHASE #define _CH_PHASE(ctx, inc) do { \ if(ctx->phase == 0) \ ctx->context = 0; \ ctx->phase += inc; \ } while(0) #define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) #define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) #undef ADVANCE #define ADVANCE(num_bytes) do { \ size_t num = (num_bytes); \ buf_ptr = ((const char *)buf_ptr) + num; \ size -= num; \ consumed_myself += num; \ } while(0) #undef RETURN #define RETURN(_code) do { \ asn_dec_rval_t tmprval; \ tmprval.code = _code; \ tmprval.consumed = consumed_myself; \ return tmprval; \ } while(0) #undef APPEND #define APPEND(bufptr, bufsize) do { \ size_t _bs = (bufsize); /* Append size */ \ size_t _ns = ctx->context; /* Allocated now */ \ size_t _es = st->size + _bs; /* Expected size */ \ /* int is really a typeof(st->size): */ \ if((int)_es < 0) RETURN(RC_FAIL); \ if(_ns <= _es) { \ void *ptr; \ /* Be nice and round to the memory allocator */ \ do { _ns = _ns ? _ns << 1 : 16; } \ while(_ns <= _es); \ /* int is really a typeof(st->size): */ \ if((int)_ns < 0) RETURN(RC_FAIL); \ ptr = REALLOC(st->buf, _ns); \ if(ptr) { \ st->buf = (uint8_t *)ptr; \ ctx->context = _ns; \ } else { \ RETURN(RC_FAIL); \ } \ ASN_DEBUG("Reallocating into %ld", (long)_ns); \ } \ memcpy(st->buf + st->size, bufptr, _bs); \ /* Convenient nul-termination */ \ st->buf[_es] = '\0'; \ st->size = _es; \ } while(0) /* * The main reason why ASN.1 is still alive is that too much time and effort * is necessary for learning it more or less adequately, thus creating a gut * necessity to demonstrate that aquired skill everywhere afterwards. * No, I am not going to explain what the following stuff is. */ struct _stack_el { ber_tlv_len_t left; /* What's left to read (or -1) */ ber_tlv_len_t got; /* What was actually processed */ int cont_level; /* Depth of subcontainment */ int want_nulls; /* Want null "end of content" octets? */ int bits_chopped; /* Flag in BIT STRING mode */ ber_tlv_tag_t tag; /* For debugging purposes */ struct _stack_el *prev; struct _stack_el *next; }; struct _stack { struct _stack_el *tail; struct _stack_el *cur_ptr; }; static struct _stack_el * OS__add_stack_el(struct _stack *st) { struct _stack_el *nel; /* * Reuse the old stack frame or allocate a new one. */ if(st->cur_ptr && st->cur_ptr->next) { nel = st->cur_ptr->next; nel->bits_chopped = 0; nel->got = 0; /* Retain the nel->cont_level, it's correct. */ } else { nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el)); if(nel == NULL) return NULL; if(st->tail) { /* Increase a subcontainment depth */ nel->cont_level = st->tail->cont_level + 1; st->tail->next = nel; } nel->prev = st->tail; st->tail = nel; } st->cur_ptr = nel; return nel; } static struct _stack * _new_stack() { return (struct _stack *)CALLOC(1, sizeof(struct _stack)); } /* * Decode OCTET STRING type. */ asn_dec_rval_t OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buf_ptr, size_t size, int tag_mode) { asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; BIT_STRING_t *st = (BIT_STRING_t *)*sptr; asn_dec_rval_t rval; asn_struct_ctx_t *ctx; ssize_t consumed_myself = 0; struct _stack *stck; /* Expectations stack structure */ struct _stack_el *sel = 0; /* Stack element */ int tlv_constr; enum asn_OS_Subvariant type_variant = specs->subvariant; ASN_DEBUG("Decoding %s as %s (frame %ld)", td->name, (type_variant == ASN_OSUBV_STR) ? "OCTET STRING" : "OS-SpecialCase", (long)size); /* * Create the string if does not exist. */ if(st == NULL) { st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); if(st == NULL) RETURN(RC_FAIL); } /* Restore parsing context */ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); switch(ctx->phase) { case 0: /* * Check tags. */ rval = ber_check_tags(opt_codec_ctx, td, ctx, buf_ptr, size, tag_mode, -1, &ctx->left, &tlv_constr); if(rval.code != RC_OK) return rval; if(tlv_constr) { /* * Complex operation, requires stack of expectations. */ ctx->ptr = _new_stack(); if(ctx->ptr) { stck = (struct _stack *)ctx->ptr; } else { RETURN(RC_FAIL); } } else { /* * Jump into stackless primitive decoding. */ _CH_PHASE(ctx, 3); if(type_variant == ASN_OSUBV_ANY && tag_mode != 1) APPEND(buf_ptr, rval.consumed); ADVANCE(rval.consumed); goto phase3; } NEXT_PHASE(ctx); /* Fall through */ case 1: phase1: /* * Fill the stack with expectations. */ stck = (struct _stack *)ctx->ptr; sel = stck->cur_ptr; do { ber_tlv_tag_t tlv_tag; ber_tlv_len_t tlv_len; ber_tlv_tag_t expected_tag; ssize_t tl, ll, tlvl; /* This one works even if (sel->left == -1) */ ssize_t Left = ((!sel||(size_t)sel->left >= size) ?(ssize_t)size:sel->left); ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel, (long)(sel?sel->left:0), (long)(sel?sel->want_nulls:0), (long)(sel?sel->got:0) ); if(sel && sel->left <= 0 && sel->want_nulls == 0) { if(sel->prev) { struct _stack_el *prev = sel->prev; if(prev->left != -1) { if(prev->left < sel->got) RETURN(RC_FAIL); prev->left -= sel->got; } prev->got += sel->got; sel = stck->cur_ptr = prev; if(!sel) break; tlv_constr = 1; continue; } else { sel = stck->cur_ptr = 0; break; /* Nothing to wait */ } } tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag); ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld", (long)size, (long)Left, sel?"":"!", (long)(sel?sel->left:0), (long)(sel?sel->want_nulls:0), (long)tl); switch(tl) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr); ll = ber_fetch_length(tlv_constr, (const char *)buf_ptr + tl,Left - tl,&tlv_len); ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld", ber_tlv_tag_string(tlv_tag), tlv_constr, (long)Left, (long)tl, (long)tlv_len, (long)ll); switch(ll) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } if(sel && sel->want_nulls && ((const uint8_t *)buf_ptr)[0] == 0 && ((const uint8_t *)buf_ptr)[1] == 0) { ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); if(type_variant == ASN_OSUBV_ANY && (tag_mode != 1 || sel->cont_level)) APPEND("\0\0", 2); ADVANCE(2); sel->got += 2; if(sel->left != -1) { sel->left -= 2; /* assert(sel->left >= 2) */ } sel->want_nulls--; if(sel->want_nulls == 0) { /* Move to the next expectation */ sel->left = 0; tlv_constr = 1; } continue; } /* * Set up expected tags, * depending on ASN.1 type being decoded. */ switch(type_variant) { case ASN_OSUBV_BIT: /* X.690: 8.6.4.1, NOTE 2 */ /* Fall through */ case ASN_OSUBV_STR: default: if(sel) { int level = sel->cont_level; if(level < td->all_tags_count) { expected_tag = td->all_tags[level]; break; } else if(td->all_tags_count) { expected_tag = td->all_tags [td->all_tags_count - 1]; break; } /* else, Fall through */ } /* Fall through */ case ASN_OSUBV_ANY: expected_tag = tlv_tag; break; } if(tlv_tag != expected_tag) { char buf[2][32]; ber_tlv_tag_snprint(tlv_tag, buf[0], sizeof(buf[0])); ber_tlv_tag_snprint(td->tags[td->tags_count-1], buf[1], sizeof(buf[1])); ASN_DEBUG("Tag does not match expectation: %s != %s", buf[0], buf[1]); RETURN(RC_FAIL); } tlvl = tl + ll; /* Combined length of T and L encoding */ if((tlv_len + tlvl) < 0) { /* tlv_len value is too big */ ASN_DEBUG("TLV encoding + length (%ld) is too big", (long)tlv_len); RETURN(RC_FAIL); } /* * Append a new expectation. */ sel = OS__add_stack_el(stck); if(!sel) RETURN(RC_FAIL); sel->tag = tlv_tag; sel->want_nulls = (tlv_len==-1); if(sel->prev && sel->prev->left != -1) { /* Check that the parent frame is big enough */ if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len)) RETURN(RC_FAIL); if(tlv_len == -1) sel->left = sel->prev->left - tlvl; else sel->left = tlv_len; } else { sel->left = tlv_len; } if(type_variant == ASN_OSUBV_ANY && (tag_mode != 1 || sel->cont_level)) APPEND(buf_ptr, tlvl); sel->got += tlvl; ADVANCE(tlvl); ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d", (long)sel->got, (long)sel->left, sel->want_nulls, sel->cont_level); } while(tlv_constr); if(sel == NULL) { /* Finished operation, "phase out" */ ASN_DEBUG("Phase out"); _CH_PHASE(ctx, +3); break; } NEXT_PHASE(ctx); /* Fall through */ case 2: stck = (struct _stack *)ctx->ptr; sel = stck->cur_ptr; ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d", (long)sel->left, (long)size, (long)sel->got, sel->want_nulls); { ber_tlv_len_t len; assert(sel->left >= 0); len = ((ber_tlv_len_t)size < sel->left) ? (ber_tlv_len_t)size : sel->left; if(len > 0) { if(type_variant == ASN_OSUBV_BIT && sel->bits_chopped == 0) { /* Put the unused-bits-octet away */ st->bits_unused = *(const uint8_t *)buf_ptr; APPEND(((const char *)buf_ptr+1), (len - 1)); sel->bits_chopped = 1; } else { APPEND(buf_ptr, len); } ADVANCE(len); sel->left -= len; sel->got += len; } if(sel->left) { ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n", (long)sel->left, (long)size, sel->want_nulls); RETURN(RC_WMORE); } PREV_PHASE(ctx); goto phase1; } break; case 3: phase3: /* * Primitive form, no stack required. */ assert(ctx->left >= 0); if(size < (size_t)ctx->left) { if(!size) RETURN(RC_WMORE); if(type_variant == ASN_OSUBV_BIT && !ctx->context) { st->bits_unused = *(const uint8_t *)buf_ptr; ctx->left--; ADVANCE(1); } APPEND(buf_ptr, size); assert(ctx->context > 0); ctx->left -= size; ADVANCE(size); RETURN(RC_WMORE); } else { if(type_variant == ASN_OSUBV_BIT && !ctx->context && ctx->left) { st->bits_unused = *(const uint8_t *)buf_ptr; ctx->left--; ADVANCE(1); } APPEND(buf_ptr, ctx->left); ADVANCE(ctx->left); ctx->left = 0; NEXT_PHASE(ctx); } break; } if(sel) { ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld", sel->prev, sel->want_nulls, (long)sel->left, (long)sel->got, (long)size); if(sel->prev || sel->want_nulls > 1 || sel->left > 0) { RETURN(RC_WMORE); } } /* * BIT STRING-specific processing. */ if(type_variant == ASN_OSUBV_BIT && st->size) { /* Finalize BIT STRING: zero out unused bits. */ st->buf[st->size-1] &= 0xff << st->bits_unused; } ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", (long)consumed_myself, td->name, (type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "", (long)st->size); RETURN(RC_OK); } /* * Encode OCTET STRING type using DER. */ asn_enc_rval_t OCTET_STRING_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 er; asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; BIT_STRING_t *st = (BIT_STRING_t *)sptr; enum asn_OS_Subvariant type_variant = specs->subvariant; int fix_last_byte = 0; ASN_DEBUG("%s %s as OCTET STRING", cb?"Estimating":"Encoding", td->name); /* * Write tags. */ if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) { er.encoded = der_write_tags(td, (type_variant == ASN_OSUBV_BIT) + st->size, tag_mode, type_variant == ASN_OSUBV_ANY, tag, cb, app_key); if(er.encoded == -1) { er.failed_type = td; er.structure_ptr = sptr; return er; } } else { /* Disallow: [] IMPLICIT ANY */ assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1); er.encoded = 0; } if(!cb) { er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size; _ASN_ENCODED_OK(er); } /* * Prepare to deal with the last octet of BIT STRING. */ if(type_variant == ASN_OSUBV_BIT) { uint8_t b = st->bits_unused & 0x07; if(b && st->size) fix_last_byte = 1; _ASN_CALLBACK(&b, 1); er.encoded++; } /* Invoke callback for the main part of the buffer */ _ASN_CALLBACK(st->buf, st->size - fix_last_byte); /* The last octet should be stripped off the unused bits */ if(fix_last_byte) { uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused); _ASN_CALLBACK(&b, 1); } er.encoded += st->size; _ASN_ENCODED_OK(er); cb_failed: _ASN_ENCODE_FAILED; } asn_enc_rval_t OCTET_STRING_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) { static const char *h2c = "0123456789ABCDEF"; const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; asn_enc_rval_t er; char scratch[16 * 3 + 4]; char *p = scratch; uint8_t *buf; uint8_t *end; size_t i; if(!st || (!st->buf && st->size)) _ASN_ENCODE_FAILED; er.encoded = 0; /* * Dump the contents of the buffer in hexadecimal. */ buf = st->buf; end = buf + st->size; if(flags & XER_F_CANONICAL) { char *scend = scratch + (sizeof(scratch) - 2); for(; buf < end; buf++) { if(p >= scend) { _ASN_CALLBACK(scratch, p - scratch); er.encoded += p - scratch; p = scratch; } *p++ = h2c[(*buf >> 4) & 0x0F]; *p++ = h2c[*buf & 0x0F]; } _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ er.encoded += p - scratch; } else { for(i = 0; buf < end; buf++, i++) { if(!(i % 16) && (i || st->size > 16)) { _ASN_CALLBACK(scratch, p-scratch); er.encoded += (p-scratch); p = scratch; _i_ASN_TEXT_INDENT(1, ilevel); } *p++ = h2c[(*buf >> 4) & 0x0F]; *p++ = h2c[*buf & 0x0F]; *p++ = 0x20; } if(p - scratch) { p--; /* Remove the tail space */ _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ er.encoded += p - scratch; if(st->size > 16) _i_ASN_TEXT_INDENT(1, ilevel-1); } } _ASN_ENCODED_OK(er); cb_failed: _ASN_ENCODE_FAILED; } static struct OCTET_STRING__xer_escape_table_s { char *string; int size; } OCTET_STRING__xer_escape_table[] = { #define OSXET(s) { s, sizeof(s) - 1 } OSXET("\074\156\165\154\057\076"), /* */ OSXET("\074\163\157\150\057\076"), /* */ OSXET("\074\163\164\170\057\076"), /* */ OSXET("\074\145\164\170\057\076"), /* */ OSXET("\074\145\157\164\057\076"), /* */ OSXET("\074\145\156\161\057\076"), /* */ OSXET("\074\141\143\153\057\076"), /* */ OSXET("\074\142\145\154\057\076"), /* */ OSXET("\074\142\163\057\076"), /* */ OSXET("\011"), /* \t */ OSXET("\012"), /* \n */ OSXET("\074\166\164\057\076"), /* */ OSXET("\074\146\146\057\076"), /* */ OSXET("\015"), /* \r */ OSXET("\074\163\157\057\076"), /* */ OSXET("\074\163\151\057\076"), /* */ OSXET("\074\144\154\145\057\076"), /* */ OSXET("\074\144\143\061\057\076"), /* */ OSXET("\074\144\143\062\057\076"), /* */ OSXET("\074\144\143\063\057\076"), /* */ OSXET("\074\144\143\064\057\076"), /* */ OSXET("\074\156\141\153\057\076"), /* */ OSXET("\074\163\171\156\057\076"), /* */ OSXET("\074\145\164\142\057\076"), /* */ OSXET("\074\143\141\156\057\076"), /* */ OSXET("\074\145\155\057\076"), /* */ OSXET("\074\163\165\142\057\076"), /* */ OSXET("\074\145\163\143\057\076"), /* */ OSXET("\074\151\163\064\057\076"), /* */ OSXET("\074\151\163\063\057\076"), /* */ OSXET("\074\151\163\062\057\076"), /* */ OSXET("\074\151\163\061\057\076"), /* */ { 0, 0 }, /* " " */ { 0, 0 }, /* ! */ { 0, 0 }, /* \" */ { 0, 0 }, /* # */ { 0, 0 }, /* $ */ { 0, 0 }, /* % */ OSXET("\046\141\155\160\073"), /* & */ { 0, 0 }, /* ' */ {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */ {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */ {0,0},{0,0},{0,0},{0,0}, /* 89:; */ OSXET("\046\154\164\073"), /* < */ { 0, 0 }, /* = */ OSXET("\046\147\164\073"), /* > */ }; static int OS__check_escaped_control_char(const void *buf, int size) { size_t i; /* * Inefficient algorithm which translates the escape sequences * defined above into characters. Returns -1 if not found. * TODO: replace by a faster algorithm (bsearch(), hash or * nested table lookups). */ for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { struct OCTET_STRING__xer_escape_table_s *el; el = &OCTET_STRING__xer_escape_table[i]; if(el->size == size && memcmp(buf, el->string, size) == 0) return i; } return -1; } static int OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) { /* * This might be one of the escape sequences * for control characters. Check it out. * #11.15.5 */ int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size); if(control_char >= 0) { OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr; void *p = REALLOC(st->buf, st->size + 2); if(p) { st->buf = (uint8_t *)p; st->buf[st->size++] = control_char; st->buf[st->size] = '\0'; /* nul-termination */ return 0; } } return -1; /* No, it's not */ } asn_enc_rval_t OCTET_STRING_encode_xer_utf8(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 OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; asn_enc_rval_t er; uint8_t *buf, *end; uint8_t *ss; /* Sequence start */ ssize_t encoded_len = 0; (void)ilevel; /* Unused argument */ (void)flags; /* Unused argument */ if(!st || (!st->buf && st->size)) _ASN_ENCODE_FAILED; buf = st->buf; end = buf + st->size; for(ss = buf; buf < end; buf++) { unsigned int ch = *buf; int s_len; /* Special encoding sequence length */ /* * Escape certain characters: X.680/11.15 */ if(ch < sizeof(OCTET_STRING__xer_escape_table) /sizeof(OCTET_STRING__xer_escape_table[0]) && (s_len = OCTET_STRING__xer_escape_table[ch].size)) { if(((buf - ss) && cb(ss, buf - ss, app_key) < 0) || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, app_key) < 0) _ASN_ENCODE_FAILED; encoded_len += (buf - ss) + s_len; ss = buf + 1; } } encoded_len += (buf - ss); if((buf - ss) && cb(ss, buf - ss, app_key) < 0) _ASN_ENCODE_FAILED; er.encoded = encoded_len; _ASN_ENCODED_OK(er); } /* * Convert from hexadecimal format (cstring): "AB CD EF" */ static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; const char *chunk_stop = (const char *)chunk_buf; const char *p = chunk_stop; const char *pend = p + chunk_size; unsigned int clv = 0; int half = 0; /* Half bit */ uint8_t *buf; /* Reallocate buffer according to high cap estimation */ ssize_t _ns = st->size + (chunk_size + 1) / 2; void *nptr = REALLOC(st->buf, _ns + 1); if(!nptr) return -1; st->buf = (uint8_t *)nptr; buf = st->buf + st->size; /* * If something like " a b c " appears here, the " a b":3 will be * converted, and the rest skipped. That is, unless buf_size is greater * than chunk_size, then it'll be equivalent to "ABC0". */ for(; p < pend; p++) { int ch = *(const unsigned char *)p; switch(ch) { case 0x09: case 0x0a: case 0x0c: case 0x0d: case 0x20: /* Ignore whitespace */ continue; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ clv = (clv << 4) + (ch - 0x30); break; case 0x41: case 0x42: case 0x43: /* ABC */ case 0x44: case 0x45: case 0x46: /* DEF */ clv = (clv << 4) + (ch - 0x41 + 10); break; case 0x61: case 0x62: case 0x63: /* abc */ case 0x64: case 0x65: case 0x66: /* def */ clv = (clv << 4) + (ch - 0x61 + 10); break; default: *buf = 0; /* JIC */ return -1; } if(half++) { half = 0; *buf++ = clv; chunk_stop = p + 1; } } /* * Check partial decoding. */ if(half) { if(have_more) { /* * Partial specification is fine, * because no more more PXER_TEXT data is available. */ *buf++ = clv << 4; chunk_stop = p; } } else { chunk_stop = p; } st->size = buf - st->buf; /* Adjust the buffer size */ assert(st->size <= _ns); st->buf[st->size] = 0; /* Courtesy termination */ return (chunk_stop - (const char *)chunk_buf); /* Converted size */ } /* * Convert from binary format: "00101011101" */ static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { BIT_STRING_t *st = (BIT_STRING_t *)sptr; const char *p = (const char *)chunk_buf; const char *pend = p + chunk_size; int bits_unused = st->bits_unused & 0x7; uint8_t *buf; /* Reallocate buffer according to high cap estimation */ ssize_t _ns = st->size + (chunk_size + 7) / 8; void *nptr = REALLOC(st->buf, _ns + 1); if(!nptr) return -1; st->buf = (uint8_t *)nptr; buf = st->buf + st->size; (void)have_more; if(bits_unused == 0) bits_unused = 8; else if(st->size) buf--; /* * Convert series of 0 and 1 into the octet string. */ for(; p < pend; p++) { int ch = *(const unsigned char *)p; switch(ch) { case 0x09: case 0x0a: case 0x0c: case 0x0d: case 0x20: /* Ignore whitespace */ break; case 0x30: case 0x31: if(bits_unused-- <= 0) { *++buf = 0; /* Clean the cell */ bits_unused = 7; } *buf |= (ch&1) << bits_unused; break; default: st->bits_unused = bits_unused; return -1; } } if(bits_unused == 8) { st->size = buf - st->buf; st->bits_unused = 0; } else { st->size = buf - st->buf + 1; st->bits_unused = bits_unused; } assert(st->size <= _ns); st->buf[st->size] = 0; /* Courtesy termination */ return chunk_size; /* Converted in full */ } /* * Something like strtod(), but with stricter rules. */ static int OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { int32_t val = 0; const char *p; for(p = buf; p < end; p++) { int ch = *p; /* Strange huge value */ if((val * base + base) < 0) return -1; switch(ch) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ val = val * base + (ch - 0x30); break; case 0x41: case 0x42: case 0x43: /* ABC */ case 0x44: case 0x45: case 0x46: /* DEF */ val = val * base + (ch - 0x41 + 10); break; case 0x61: case 0x62: case 0x63: /* abc */ case 0x64: case 0x65: case 0x66: /* def */ val = val * base + (ch - 0x61 + 10); break; case 0x3b: /* ';' */ *ret_value = val; return (p - buf) + 1; default: return -1; /* Character set error */ } } *ret_value = -1; return (p - buf); } /* * Convert from the plain UTF-8 format, expanding entity references: "2 < 3" */ static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; const char *p = (const char *)chunk_buf; const char *pend = p + chunk_size; uint8_t *buf; /* Reallocate buffer */ ssize_t _ns = st->size + chunk_size; void *nptr = REALLOC(st->buf, _ns + 1); if(!nptr) return -1; st->buf = (uint8_t *)nptr; buf = st->buf + st->size; /* * Convert series of 0 and 1 into the octet string. */ for(; p < pend; p++) { int ch = *(const unsigned char *)p; int len; /* Length of the rest of the chunk */ if(ch != 0x26 /* '&' */) { *buf++ = ch; continue; /* That was easy... */ } /* * Process entity reference. */ len = chunk_size - (p - (const char *)chunk_buf); if(len == 1 /* "&" */) goto want_more; if(p[1] == 0x23 /* '#' */) { const char *pval; /* Pointer to start of digits */ int32_t val = 0; /* Entity reference value */ int base; if(len == 2 /* "&#" */) goto want_more; if(p[2] == 0x78 /* 'x' */) pval = p + 3, base = 16; else pval = p + 2, base = 10; len = OS__strtoent(base, pval, p + len, &val); if(len == -1) { /* Invalid charset. Just copy verbatim. */ *buf++ = ch; continue; } if(!len || pval[len-1] != 0x3b) goto want_more; assert(val > 0); p += (pval - p) + len - 1; /* Advance past entref */ if(val < 0x80) { *buf++ = (char)val; } else if(val < 0x800) { *buf++ = 0xc0 | ((val >> 6)); *buf++ = 0x80 | ((val & 0x3f)); } else if(val < 0x10000) { *buf++ = 0xe0 | ((val >> 12)); *buf++ = 0x80 | ((val >> 6) & 0x3f); *buf++ = 0x80 | ((val & 0x3f)); } else if(val < 0x200000) { *buf++ = 0xf0 | ((val >> 18)); *buf++ = 0x80 | ((val >> 12) & 0x3f); *buf++ = 0x80 | ((val >> 6) & 0x3f); *buf++ = 0x80 | ((val & 0x3f)); } else if(val < 0x4000000) { *buf++ = 0xf8 | ((val >> 24)); *buf++ = 0x80 | ((val >> 18) & 0x3f); *buf++ = 0x80 | ((val >> 12) & 0x3f); *buf++ = 0x80 | ((val >> 6) & 0x3f); *buf++ = 0x80 | ((val & 0x3f)); } else { *buf++ = 0xfc | ((val >> 30) & 0x1); *buf++ = 0x80 | ((val >> 24) & 0x3f); *buf++ = 0x80 | ((val >> 18) & 0x3f); *buf++ = 0x80 | ((val >> 12) & 0x3f); *buf++ = 0x80 | ((val >> 6) & 0x3f); *buf++ = 0x80 | ((val & 0x3f)); } } else { /* * Ugly, limited parsing of & > < */ char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len); if(!sc) goto want_more; if((sc - p) == 4 && p[1] == 0x61 /* 'a' */ && p[2] == 0x6d /* 'm' */ && p[3] == 0x70 /* 'p' */) { *buf++ = 0x26; p = sc; continue; } if((sc - p) == 3) { if(p[1] == 0x6c) { *buf = 0x3c; /* '<' */ } else if(p[1] == 0x67) { *buf = 0x3e; /* '>' */ } else { /* Unsupported entity reference */ *buf++ = ch; continue; } if(p[2] != 0x74) { /* Unsupported entity reference */ *buf++ = ch; continue; } buf++; p = sc; continue; } /* Unsupported entity reference */ *buf++ = ch; } continue; want_more: if(have_more) { /* * We know that no more data (of the same type) * is coming. Copy the rest verbatim. */ *buf++ = ch; continue; } chunk_size = (p - (const char *)chunk_buf); /* Processing stalled: need more data */ break; } st->size = buf - st->buf; assert(st->size <= _ns); st->buf[st->size] = 0; /* Courtesy termination */ return chunk_size; /* Converted in full */ } /* * Decode OCTET STRING from the XML element's body. */ static asn_dec_rval_t OCTET_STRING__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, int (*opt_unexpected_tag_decoder) (void *struct_ptr, const void *chunk_buf, size_t chunk_size), ssize_t (*body_receiver) (void *struct_ptr, const void *chunk_buf, size_t chunk_size, int have_more) ) { OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; asn_struct_ctx_t *ctx; /* Per-structure parser context */ asn_dec_rval_t rval; /* Return value from the decoder */ int st_allocated; /* * Create the string if does not exist. */ if(!st) { st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); *sptr = (void *)st; if(!st) goto sta_failed; st_allocated = 1; } else { st_allocated = 0; } if(!st->buf) { /* This is separate from above section */ st->buf = (uint8_t *)CALLOC(1, 1); if(!st->buf) { if(st_allocated) { *sptr = 0; goto stb_failed; } else { goto sta_failed; } } } /* Restore parsing context */ ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset); return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag, buf_ptr, size, opt_unexpected_tag_decoder, body_receiver); stb_failed: FREEMEM(st); sta_failed: rval.code = RC_FAIL; rval.consumed = 0; return rval; } /* * Decode OCTET STRING from the hexadecimal data. */ asn_dec_rval_t OCTET_STRING_decode_xer_hex(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 OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal); } /* * Decode OCTET STRING from the binary (0/1) data. */ asn_dec_rval_t OCTET_STRING_decode_xer_binary(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 OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, buf_ptr, size, 0, OCTET_STRING__convert_binary); } /* * Decode OCTET STRING from the string (ASCII/UTF-8) data. */ asn_dec_rval_t OCTET_STRING_decode_xer_utf8(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 OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, buf_ptr, size, OCTET_STRING__handle_control_chars, OCTET_STRING__convert_entrefs); } static int OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, size_t units, unsigned int bpc, unsigned int unit_bits, long lb, long ub, asn_per_constraints_t *pc) { uint8_t *end = buf + units * bpc; ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", (int)units, lb, ub, unit_bits); /* X.691: 27.5.4 */ if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { /* Decode without translation */ lb = 0; } else if(pc && pc->code2value) { if(unit_bits > 16) return 1; /* FATAL: can't have constrained * UniversalString with more than * 16 million code points */ for(; buf < end; buf += bpc) { int value; int code = per_get_few_bits(po, unit_bits); if(code < 0) return -1; /* WMORE */ value = pc->code2value(code); if(value < 0) { ASN_DEBUG("Code %d (0x%02x) is" " not in map (%ld..%ld)", code, code, lb, ub); return 1; /* FATAL */ } switch(bpc) { case 1: *buf = value; break; case 2: buf[0] = value >> 8; buf[1] = value; break; case 4: buf[0] = value >> 24; buf[1] = value >> 16; buf[2] = value >> 8; buf[3] = value; break; } } return 0; } /* Shortcut the no-op copying to the aligned structure */ if(lb == 0 && (unit_bits == 8 * bpc)) { return per_get_many_bits(po, buf, 0, unit_bits * units); } for(; buf < end; buf += bpc) { int code = per_get_few_bits(po, unit_bits); int ch = code + lb; if(code < 0) return -1; /* WMORE */ if(ch > ub) { ASN_DEBUG("Code %d is out of range (%ld..%ld)", ch, lb, ub); return 1; /* FATAL */ } switch(bpc) { case 1: *buf = ch; break; case 2: buf[0] = ch >> 8; buf[1] = ch; break; case 4: buf[0] = ch >> 24; buf[1] = ch >> 16; buf[2] = ch >> 8; buf[3] = ch; break; } } return 0; } static int OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, size_t units, unsigned int bpc, unsigned int unit_bits, long lb, long ub, asn_per_constraints_t *pc) { const uint8_t *end = buf + units * bpc; ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)", (int)units, lb, ub, unit_bits, bpc); /* X.691: 27.5.4 */ if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { /* Encode as is */ lb = 0; } else if(pc && pc->value2code) { for(; buf < end; buf += bpc) { int code; uint32_t value; switch(bpc) { case 1: value = *(const uint8_t *)buf; break; case 2: value = (buf[0] << 8) | buf[1]; break; case 4: value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; break; default: return -1; } code = pc->value2code(value); if(code < 0) { ASN_DEBUG("Character %d (0x%02x) is" " not in map (%ld..%ld)", *buf, *buf, lb, ub); return -1; } if(per_put_few_bits(po, code, unit_bits)) return -1; } } /* Shortcut the no-op copying to the aligned structure */ if(lb == 0 && (unit_bits == 8 * bpc)) { return per_put_many_bits(po, buf, unit_bits * units); } for(ub -= lb; buf < end; buf += bpc) { int ch; uint32_t value; switch(bpc) { case 1: value = *(const uint8_t *)buf; break; case 2: value = (buf[0] << 8) | buf[1]; break; case 4: value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; break; default: return -1; } ch = value - lb; if(ch < 0 || ch > ub) { ASN_DEBUG("Character %d (0x%02x)" " is out of range (%ld..%ld)", *buf, *buf, lb, ub + lb); return -1; } if(per_put_few_bits(po, ch, unit_bits)) return -1; } return 0; } asn_dec_rval_t OCTET_STRING_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_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; asn_per_constraints_t *pc = constraints ? constraints : td->per_constraints; asn_per_constraint_t *cval; asn_per_constraint_t *csiz; asn_dec_rval_t rval = { RC_OK, 0 }; BIT_STRING_t *st = (BIT_STRING_t *)*sptr; ssize_t consumed_myself = 0; int repeat; enum { OS__BPC_BIT = 0, OS__BPC_CHAR = 1, OS__BPC_U16 = 2, OS__BPC_U32 = 4 } bpc; /* Bytes per character */ unsigned int unit_bits; unsigned int canonical_unit_bits; (void)opt_codec_ctx; if(pc) { cval = &pc->value; csiz = &pc->size; } else { cval = &asn_DEF_OCTET_STRING_constraints.value; csiz = &asn_DEF_OCTET_STRING_constraints.size; } switch(specs->subvariant) { default: case ASN_OSUBV_ANY: ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant); RETURN(RC_FAIL); case ASN_OSUBV_BIT: canonical_unit_bits = unit_bits = 1; bpc = OS__BPC_BIT; break; case ASN_OSUBV_STR: canonical_unit_bits = unit_bits = 8; if(cval->flags & APC_CONSTRAINED) unit_bits = cval->range_bits; bpc = OS__BPC_CHAR; break; case ASN_OSUBV_U16: canonical_unit_bits = unit_bits = 16; if(cval->flags & APC_CONSTRAINED) unit_bits = cval->range_bits; bpc = OS__BPC_U16; break; case ASN_OSUBV_U32: canonical_unit_bits = unit_bits = 32; if(cval->flags & APC_CONSTRAINED) unit_bits = cval->range_bits; bpc = OS__BPC_U32; break; } /* * Allocate the string. */ if(!st) { st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); if(!st) RETURN(RC_FAIL); } ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); if(csiz->flags & APC_EXTENSIBLE) { int inext = per_get_few_bits(pd, 1); if(inext < 0) RETURN(RC_WMORE); if(inext) { csiz = &asn_DEF_OCTET_STRING_constraints.size; cval = &asn_DEF_OCTET_STRING_constraints.value; unit_bits = canonical_unit_bits; } } if(csiz->effective_bits >= 0) { FREEMEM(st->buf); if(bpc) { st->size = csiz->upper_bound * bpc; } else { st->size = (csiz->upper_bound + 7) >> 3; } st->buf = (uint8_t *)MALLOC(st->size + 1); if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } } /* X.691, #16.5: zero-length encoding */ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ if(csiz->effective_bits == 0) { int ret; if(bpc) { ASN_DEBUG("Encoding OCTET STRING size %ld", csiz->upper_bound); ret = OCTET_STRING_per_get_characters(pd, st->buf, csiz->upper_bound, bpc, unit_bits, cval->lower_bound, cval->upper_bound, pc); if(ret > 0) RETURN(RC_FAIL); } else { ASN_DEBUG("Encoding BIT STRING size %ld", csiz->upper_bound); ret = per_get_many_bits(pd, st->buf, 0, unit_bits * csiz->upper_bound); } if(ret < 0) RETURN(RC_WMORE); consumed_myself += unit_bits * csiz->upper_bound; st->buf[st->size] = 0; if(bpc == 0) { int ubs = (csiz->upper_bound & 0x7); st->bits_unused = ubs ? 8 - ubs : 0; } RETURN(RC_OK); } st->size = 0; do { ssize_t raw_len; ssize_t len_bytes; ssize_t len_bits; void *p; int ret; /* Get the PER length */ raw_len = uper_get_length(pd, csiz->effective_bits, &repeat); if(raw_len < 0) RETURN(RC_WMORE); raw_len += csiz->lower_bound; ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", (long)csiz->effective_bits, (long)raw_len, repeat ? "repeat" : "once", td->name); if(bpc) { len_bytes = raw_len * bpc; len_bits = len_bytes * unit_bits; } else { len_bits = raw_len; len_bytes = (len_bits + 7) >> 3; if(len_bits & 0x7) st->bits_unused = 8 - (len_bits & 0x7); /* len_bits be multiple of 16K if repeat is set */ } p = REALLOC(st->buf, st->size + len_bytes + 1); if(!p) RETURN(RC_FAIL); st->buf = (uint8_t *)p; if(bpc) { ret = OCTET_STRING_per_get_characters(pd, &st->buf[st->size], raw_len, bpc, unit_bits, cval->lower_bound, cval->upper_bound, pc); if(ret > 0) RETURN(RC_FAIL); } else { ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits); } if(ret < 0) RETURN(RC_WMORE); st->size += len_bytes; } while(repeat); st->buf[st->size] = 0; /* nul-terminate */ return rval; } asn_enc_rval_t OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; asn_per_constraints_t *pc = constraints ? constraints : td->per_constraints; asn_per_constraint_t *cval; asn_per_constraint_t *csiz; const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; asn_enc_rval_t er = { 0, 0, 0 }; int inext = 0; /* Lies not within extension root */ unsigned int unit_bits; unsigned int canonical_unit_bits; unsigned int sizeinunits; const uint8_t *buf; int ret; enum { OS__BPC_BIT = 0, OS__BPC_CHAR = 1, OS__BPC_U16 = 2, OS__BPC_U32 = 4 } bpc; /* Bytes per character */ int ct_extensible; if(!st || (!st->buf && st->size)) _ASN_ENCODE_FAILED; if(pc) { cval = &pc->value; csiz = &pc->size; } else { cval = &asn_DEF_OCTET_STRING_constraints.value; csiz = &asn_DEF_OCTET_STRING_constraints.size; } ct_extensible = csiz->flags & APC_EXTENSIBLE; switch(specs->subvariant) { default: case ASN_OSUBV_ANY: _ASN_ENCODE_FAILED; case ASN_OSUBV_BIT: canonical_unit_bits = unit_bits = 1; bpc = OS__BPC_BIT; sizeinunits = st->size * 8 - (st->bits_unused & 0x07); ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", sizeinunits, st->bits_unused); break; case ASN_OSUBV_STR: canonical_unit_bits = unit_bits = 8; if(cval->flags & APC_CONSTRAINED) unit_bits = cval->range_bits; bpc = OS__BPC_CHAR; sizeinunits = st->size; break; case ASN_OSUBV_U16: canonical_unit_bits = unit_bits = 16; if(cval->flags & APC_CONSTRAINED) unit_bits = cval->range_bits; bpc = OS__BPC_U16; sizeinunits = st->size / 2; break; case ASN_OSUBV_U32: canonical_unit_bits = unit_bits = 32; if(cval->flags & APC_CONSTRAINED) unit_bits = cval->range_bits; bpc = OS__BPC_U32; sizeinunits = st->size / 4; break; } ASN_DEBUG("Encoding %s into %d units of %d bits" " (%ld..%ld, effective %d)%s", td->name, sizeinunits, unit_bits, csiz->lower_bound, csiz->upper_bound, csiz->effective_bits, ct_extensible ? " EXT" : ""); /* Figure out whether size lies within PER visible constraint */ if(csiz->effective_bits >= 0) { if((int)sizeinunits < csiz->lower_bound || (int)sizeinunits > csiz->upper_bound) { if(ct_extensible) { cval = &asn_DEF_OCTET_STRING_constraints.value; csiz = &asn_DEF_OCTET_STRING_constraints.size; unit_bits = canonical_unit_bits; inext = 1; } else _ASN_ENCODE_FAILED; } } else { inext = 0; } if(ct_extensible) { /* Declare whether length is [not] within extension root */ if(per_put_few_bits(po, inext, 1)) _ASN_ENCODE_FAILED; } /* X.691, #16.5: zero-length encoding */ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ if(csiz->effective_bits >= 0) { ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", st->size, sizeinunits - csiz->lower_bound, csiz->effective_bits); ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound, csiz->effective_bits); if(ret) _ASN_ENCODE_FAILED; if(bpc) { ret = OCTET_STRING_per_put_characters(po, st->buf, sizeinunits, bpc, unit_bits, cval->lower_bound, cval->upper_bound, pc); } else { ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits); } if(ret) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } ASN_DEBUG("Encoding %d bytes", st->size); if(sizeinunits == 0) { if(uper_put_length(po, 0)) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } buf = st->buf; while(sizeinunits) { ssize_t maySave = uper_put_length(po, sizeinunits); if(maySave < 0) _ASN_ENCODE_FAILED; ASN_DEBUG("Encoding %ld of %ld", (long)maySave, (long)sizeinunits); if(bpc) { ret = OCTET_STRING_per_put_characters(po, buf, maySave, bpc, unit_bits, cval->lower_bound, cval->upper_bound, pc); } else { ret = per_put_many_bits(po, buf, maySave * unit_bits); } if(ret) _ASN_ENCODE_FAILED; if(bpc) buf += maySave * bpc; else buf += maySave >> 3; sizeinunits -= maySave; assert(!(maySave & 0x07) || !sizeinunits); } _ASN_ENCODED_OK(er); } int OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { static const char *h2c = "0123456789ABCDEF"; const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; char scratch[16 * 3 + 4]; char *p = scratch; uint8_t *buf; uint8_t *end; size_t i; (void)td; /* Unused argument */ if(!st || (!st->buf && st->size)) return (cb("", 8, app_key) < 0) ? -1 : 0; /* * Dump the contents of the buffer in hexadecimal. */ buf = st->buf; end = buf + st->size; for(i = 0; buf < end; buf++, i++) { if(!(i % 16) && (i || st->size > 16)) { if(cb(scratch, p - scratch, app_key) < 0) return -1; _i_INDENT(1); p = scratch; } *p++ = h2c[(*buf >> 4) & 0x0F]; *p++ = h2c[*buf & 0x0F]; *p++ = 0x20; } if(p > scratch) { p--; /* Remove the tail space */ if(cb(scratch, p - scratch, app_key) < 0) return -1; } return 0; } int OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; (void)td; /* Unused argument */ (void)ilevel; /* Unused argument */ if(st && (st->buf || !st->size)) { return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; } else { return (cb("", 8, app_key) < 0) ? -1 : 0; } } void OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; asn_struct_ctx_t *ctx = (asn_struct_ctx_t *) ((char *)st + specs->ctx_offset); struct _stack *stck; if(!td || !st) return; ASN_DEBUG("Freeing %s as OCTET STRING", td->name); if(st->buf) { FREEMEM(st->buf); st->buf = 0; } /* * Remove decode-time stack. */ stck = (struct _stack *)ctx->ptr; if(stck) { while(stck->tail) { struct _stack_el *sel = stck->tail; stck->tail = sel->prev; FREEMEM(sel); } FREEMEM(stck); } if(!contents_only) { FREEMEM(st); } } /* * Conversion routines. */ int OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { void *buf; if(st == 0 || (str == 0 && len)) { errno = EINVAL; return -1; } /* * Clear the OCTET STRING. */ if(str == NULL) { FREEMEM(st->buf); st->buf = 0; st->size = 0; return 0; } /* Determine the original string size, if not explicitly given */ if(len < 0) len = strlen(str); /* Allocate and fill the memory */ buf = MALLOC(len + 1); if(buf == NULL) return -1; memcpy(buf, str, len); ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */ FREEMEM(st->buf); st->buf = (uint8_t *)buf; st->size = len; return 0; } OCTET_STRING_t * OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) { asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; OCTET_STRING_t *st; st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); if(st && str && OCTET_STRING_fromBuf(st, str, len)) { FREEMEM(st); st = NULL; } return st; } mod_auth_gssapi-1.3.2/src/asn1c/OCTET_STRING.h000066400000000000000000000054031266122234600206020ustar00rootroot00000000000000/*- * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _OCTET_STRING_H_ #define _OCTET_STRING_H_ #include #ifdef __cplusplus extern "C" { #endif typedef struct OCTET_STRING { uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ int size; /* Size of the buffer */ asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ } OCTET_STRING_t; extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; asn_struct_free_f OCTET_STRING_free; asn_struct_print_f OCTET_STRING_print; asn_struct_print_f OCTET_STRING_print_utf8; ber_type_decoder_f OCTET_STRING_decode_ber; der_type_encoder_f OCTET_STRING_encode_der; xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ xer_type_encoder_f OCTET_STRING_encode_xer; xer_type_encoder_f OCTET_STRING_encode_xer_utf8; per_type_decoder_f OCTET_STRING_decode_uper; per_type_encoder_f OCTET_STRING_encode_uper; /****************************** * Handy conversion routines. * ******************************/ /* * This function clears the previous value of the OCTET STRING (if any) * and then allocates a new memory with the specified content (str/size). * If size = -1, the size of the original string will be determined * using strlen(str). * If str equals to NULL, the function will silently clear the * current contents of the OCTET STRING. * Returns 0 if it was possible to perform operation, -1 otherwise. */ int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); /* Handy conversion from the C string into the OCTET STRING. */ #define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) /* * Allocate and fill the new OCTET STRING and return a pointer to the newly * allocated object. NULL is permitted in str: the function will just allocate * empty OCTET STRING. */ OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int size); /**************************** * Internally useful stuff. * ****************************/ typedef struct asn_OCTET_STRING_specifics_s { /* * Target structure description. */ int struct_size; /* Size of the structure */ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ enum asn_OS_Subvariant { ASN_OSUBV_ANY, /* The open type (ANY) */ ASN_OSUBV_BIT, /* BIT STRING */ ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ ASN_OSUBV_U16, /* 16-bit character (BMPString) */ ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ } subvariant; } asn_OCTET_STRING_specifics_t; #ifdef __cplusplus } #endif #endif /* _OCTET_STRING_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/Uint32.c000066400000000000000000000074331266122234600177220ustar00rootroot00000000000000/* * Generated by asn1c-0.9.27 (http://lionet.info/asn1c) * From ASN.1 module "GssapiSessionModule" * found in "session.asn1" * `asn1c -fskeletons-copy` */ #include "Uint32.h" int Uint32_constraint(asn_TYPE_descriptor_t *td, const void *sptr, asn_app_constraint_failed_f *ctfailcb, void *app_key) { if(!sptr) { _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; } /* Constraint check succeeded */ return 0; } /* * This type is implemented using NativeInteger, * so here we adjust the DEF accordingly. */ static void Uint32_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { td->free_struct = asn_DEF_NativeInteger.free_struct; td->print_struct = asn_DEF_NativeInteger.print_struct; td->check_constraints = asn_DEF_NativeInteger.check_constraints; td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; td->der_encoder = asn_DEF_NativeInteger.der_encoder; td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; if(!td->per_constraints) td->per_constraints = asn_DEF_NativeInteger.per_constraints; td->elements = asn_DEF_NativeInteger.elements; td->elements_count = asn_DEF_NativeInteger.elements_count; /* td->specifics = asn_DEF_NativeInteger.specifics; // Defined explicitly */ } void Uint32_free(asn_TYPE_descriptor_t *td, void *struct_ptr, int contents_only) { Uint32_1_inherit_TYPE_descriptor(td); td->free_struct(td, struct_ptr, contents_only); } int Uint32_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { Uint32_1_inherit_TYPE_descriptor(td); return td->print_struct(td, struct_ptr, ilevel, cb, app_key); } asn_dec_rval_t Uint32_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **structure, const void *bufptr, size_t size, int tag_mode) { Uint32_1_inherit_TYPE_descriptor(td); return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); } asn_enc_rval_t Uint32_encode_der(asn_TYPE_descriptor_t *td, void *structure, int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) { Uint32_1_inherit_TYPE_descriptor(td); return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); } asn_dec_rval_t Uint32_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **structure, const char *opt_mname, const void *bufptr, size_t size) { Uint32_1_inherit_TYPE_descriptor(td); return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); } asn_enc_rval_t Uint32_encode_xer(asn_TYPE_descriptor_t *td, void *structure, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) { Uint32_1_inherit_TYPE_descriptor(td); return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); } static asn_INTEGER_specifics_t asn_SPC_Uint32_specs_1 = { 0, 0, 0, 0, 0, 0, /* Native long size */ 1 /* Unsigned representation */ }; static ber_tlv_tag_t asn_DEF_Uint32_tags_1[] = { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) }; asn_TYPE_descriptor_t asn_DEF_Uint32 = { "Uint32", "Uint32", Uint32_free, Uint32_print, Uint32_constraint, Uint32_decode_ber, Uint32_encode_der, Uint32_decode_xer, Uint32_encode_xer, 0, 0, /* No PER support, use "-gen-PER" to enable */ 0, /* Use generic outmost tag fetcher */ asn_DEF_Uint32_tags_1, sizeof(asn_DEF_Uint32_tags_1) /sizeof(asn_DEF_Uint32_tags_1[0]), /* 1 */ asn_DEF_Uint32_tags_1, /* Same as above */ sizeof(asn_DEF_Uint32_tags_1) /sizeof(asn_DEF_Uint32_tags_1[0]), /* 1 */ 0, /* No PER visible constraints */ 0, 0, /* No members */ &asn_SPC_Uint32_specs_1 /* Additional specs */ }; mod_auth_gssapi-1.3.2/src/asn1c/Uint32.h000066400000000000000000000014231266122234600177200ustar00rootroot00000000000000/* * Generated by asn1c-0.9.27 (http://lionet.info/asn1c) * From ASN.1 module "GssapiSessionModule" * found in "session.asn1" * `asn1c -fskeletons-copy` */ #ifndef _Uint32_H_ #define _Uint32_H_ #include /* Including external dependencies */ #include #ifdef __cplusplus extern "C" { #endif /* Uint32 */ typedef unsigned long Uint32_t; /* Implementation */ extern asn_TYPE_descriptor_t asn_DEF_Uint32; asn_struct_free_f Uint32_free; asn_struct_print_f Uint32_print; asn_constr_check_f Uint32_constraint; ber_type_decoder_f Uint32_decode_ber; der_type_encoder_f Uint32_encode_der; xer_type_decoder_f Uint32_decode_xer; xer_type_encoder_f Uint32_encode_xer; #ifdef __cplusplus } #endif #endif /* _Uint32_H_ */ #include mod_auth_gssapi-1.3.2/src/asn1c/asn_application.h000066400000000000000000000027161266122234600220060ustar00rootroot00000000000000/*- * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * Application-level ASN.1 callbacks. */ #ifndef _ASN_APPLICATION_H_ #define _ASN_APPLICATION_H_ #include "asn_system.h" /* for platform-dependent types */ #include "asn_codecs.h" /* for ASN.1 codecs specifics */ #ifdef __cplusplus extern "C" { #endif /* * Generic type of an application-defined callback to return various * types of data to the application. * EXPECTED RETURN VALUES: * -1: Failed to consume bytes. Abort the mission. * Non-negative return values indicate success, and ignored. */ typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, void *application_specific_key); /* * A callback of this type is called whenever constraint validation fails * on some ASN.1 type. See "constraints.h" for more details on constraint * validation. * This callback specifies a descriptor of the ASN.1 type which failed * the constraint check, as well as human readable message on what * particular constraint has failed. */ typedef void (asn_app_constraint_failed_f)(void *application_specific_key, struct asn_TYPE_descriptor_s *type_descriptor_which_failed, const void *structure_which_failed_ptr, const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); #ifdef __cplusplus } #endif #include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ #endif /* _ASN_APPLICATION_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/asn_codecs.h000066400000000000000000000065711266122234600207460ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004, 2005 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _ASN_CODECS_H_ #define _ASN_CODECS_H_ #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * This structure defines a set of parameters that may be passed * to every ASN.1 encoder or decoder function. * WARNING: if max_stack_size member is set, and you are calling the * function pointers of the asn_TYPE_descriptor_t directly, * this structure must be ALLOCATED ON THE STACK! * If you can't always satisfy this requirement, use ber_decode(), * xer_decode() and uper_decode() functions instead. */ typedef struct asn_codec_ctx_s { /* * Limit the decoder routines to use no (much) more stack than a given * number of bytes. Most of decoders are stack-based, and this * would protect against stack overflows if the number of nested * encodings is high. * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based, * and are safe from this kind of overflow. * A value from getrlimit(RLIMIT_STACK) may be used to initialize * this variable. Be careful in multithreaded environments, as the * stack size is rather limited. */ size_t max_stack_size; /* 0 disables stack bounds checking */ } asn_codec_ctx_t; /* * Type of the return value of the encoding functions (der_encode, xer_encode). */ typedef struct asn_enc_rval_s { /* * Number of bytes encoded. * -1 indicates failure to encode the structure. * In this case, the members below this one are meaningful. */ ssize_t encoded; /* * Members meaningful when (encoded == -1), for post mortem analysis. */ /* Type which cannot be encoded */ struct asn_TYPE_descriptor_s *failed_type; /* Pointer to the structure of that type */ void *structure_ptr; } asn_enc_rval_t; #define _ASN_ENCODE_FAILED do { \ asn_enc_rval_t tmp_error; \ tmp_error.encoded = -1; \ tmp_error.failed_type = td; \ tmp_error.structure_ptr = sptr; \ ASN_DEBUG("Failed to encode element %s", td ? td->name : ""); \ return tmp_error; \ } while(0) #define _ASN_ENCODED_OK(rval) do { \ rval.structure_ptr = 0; \ rval.failed_type = 0; \ return rval; \ } while(0) /* * Type of the return value of the decoding functions (ber_decode, xer_decode) * * Please note that the number of consumed bytes is ALWAYS meaningful, * even if code==RC_FAIL. This is to indicate the number of successfully * decoded bytes, hence providing a possibility to fail with more diagnostics * (i.e., print the offending remainder of the buffer). */ enum asn_dec_rval_code_e { RC_OK, /* Decoded successfully */ RC_WMORE, /* More data expected, call again */ RC_FAIL /* Failure to decode data */ }; typedef struct asn_dec_rval_s { enum asn_dec_rval_code_e code; /* Result code */ size_t consumed; /* Number of bytes consumed */ } asn_dec_rval_t; #define _ASN_DECODE_FAILED do { \ asn_dec_rval_t tmp_error; \ tmp_error.code = RC_FAIL; \ tmp_error.consumed = 0; \ ASN_DEBUG("Failed to decode element %s", td ? td->name : ""); \ return tmp_error; \ } while(0) #define _ASN_DECODE_STARVED do { \ asn_dec_rval_t tmp_error; \ tmp_error.code = RC_WMORE; \ tmp_error.consumed = 0; \ return tmp_error; \ } while(0) #ifdef __cplusplus } #endif #endif /* _ASN_CODECS_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/asn_codecs_prim.c000066400000000000000000000164311266122234600217640ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* * Decode an always-primitive type. */ asn_dec_rval_t ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buf_ptr, size_t size, int tag_mode) { ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; asn_dec_rval_t rval; ber_tlv_len_t length = 0; // =0 to avoid [incorrect] warning. /* * If the structure is not there, allocate it. */ if(st == NULL) { st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st)); if(st == NULL) _ASN_DECODE_FAILED; *sptr = (void *)st; } ASN_DEBUG("Decoding %s as plain primitive (tm=%d)", td->name, tag_mode); /* * Check tags and extract value length. */ 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("%s length is %d bytes", td->name, (int)length); /* * Make sure we have this 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; } st->size = (int)length; /* The following better be optimized away. */ if(sizeof(st->size) != sizeof(length) && (ber_tlv_len_t)st->size != length) { st->size = 0; _ASN_DECODE_FAILED; } st->buf = (uint8_t *)MALLOC(length + 1); if(!st->buf) { st->size = 0; _ASN_DECODE_FAILED; } memcpy(st->buf, buf_ptr, length); st->buf[length] = '\0'; /* Just in case */ rval.code = RC_OK; rval.consumed += length; ASN_DEBUG("Took %ld/%ld bytes to encode %s", (long)rval.consumed, (long)length, td->name); return rval; } /* * Encode an always-primitive type using DER. */ asn_enc_rval_t der_encode_primitive(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; ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; ASN_DEBUG("%s %s as a primitive type (tm=%d)", cb?"Encoding":"Estimating", td->name, tag_mode); erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag, cb, app_key); ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded); if(erval.encoded == -1) { erval.failed_type = td; erval.structure_ptr = sptr; return erval; } if(cb && st->buf) { if(cb(st->buf, st->size, app_key) < 0) { erval.encoded = -1; erval.failed_type = td; erval.structure_ptr = sptr; return erval; } } else { assert(st->buf || st->size == 0); } erval.encoded += st->size; _ASN_ENCODED_OK(erval); } void ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; if(!td || !sptr) return; ASN_DEBUG("Freeing %s as a primitive type", td->name); if(st->buf) FREEMEM(st->buf); if(!contents_only) FREEMEM(st); } /* * Local internal type passed around as an argument. */ struct xdp_arg_s { asn_TYPE_descriptor_t *type_descriptor; void *struct_key; xer_primitive_body_decoder_f *prim_body_decoder; int decoded_something; int want_more; }; /* * Since some kinds of primitive values can be encoded using value-specific * tags (, , etc), the primitive decoder must * be supplied with such tags to parse them as needed. */ static int xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) { struct xdp_arg_s *arg = (struct xdp_arg_s *)key; enum xer_pbd_rval bret; /* * The chunk_buf is guaranteed to start at '<'. */ assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c); /* * Decoding was performed once already. Prohibit doing it again. */ if(arg->decoded_something) return -1; bret = arg->prim_body_decoder(arg->type_descriptor, arg->struct_key, chunk_buf, chunk_size); switch(bret) { case XPBD_SYSTEM_FAILURE: case XPBD_DECODER_LIMIT: case XPBD_BROKEN_ENCODING: break; case XPBD_BODY_CONSUMED: /* Tag decoded successfully */ arg->decoded_something = 1; /* Fall through */ case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ return 0; } return -1; } static ssize_t xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { struct xdp_arg_s *arg = (struct xdp_arg_s *)key; enum xer_pbd_rval bret; size_t lead_wsp_size; if(arg->decoded_something) { if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) { /* * Example: * "123 " * ^- chunk_buf position. */ return chunk_size; } /* * Decoding was done once already. Prohibit doing it again. */ return -1; } if(!have_more) { /* * If we've received something like "1", we can't really * tell whether it is really `1` or `123`, until we know * that there is no more data coming. * The have_more argument will be set to 1 once something * like this is available to the caller of this callback: * "1want_more = 1; return -1; } lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size); chunk_buf = (const char *)chunk_buf + lead_wsp_size; chunk_size -= lead_wsp_size; bret = arg->prim_body_decoder(arg->type_descriptor, arg->struct_key, chunk_buf, chunk_size); switch(bret) { case XPBD_SYSTEM_FAILURE: case XPBD_DECODER_LIMIT: case XPBD_BROKEN_ENCODING: break; case XPBD_BODY_CONSUMED: /* Tag decoded successfully */ arg->decoded_something = 1; /* Fall through */ case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ return lead_wsp_size + chunk_size; } return -1; } asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, size_t struct_size, const char *opt_mname, const void *buf_ptr, size_t size, xer_primitive_body_decoder_f *prim_body_decoder ) { const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; asn_struct_ctx_t s_ctx; struct xdp_arg_s s_arg; asn_dec_rval_t rc; /* * Create the structure if does not exist. */ if(!*sptr) { *sptr = CALLOC(1, struct_size); if(!*sptr) _ASN_DECODE_FAILED; } memset(&s_ctx, 0, sizeof(s_ctx)); s_arg.type_descriptor = td; s_arg.struct_key = *sptr; s_arg.prim_body_decoder = prim_body_decoder; s_arg.decoded_something = 0; s_arg.want_more = 0; rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg, xml_tag, buf_ptr, size, xer_decode__unexpected_tag, xer_decode__primitive_body); switch(rc.code) { case RC_OK: if(!s_arg.decoded_something) { char ch; ASN_DEBUG("Primitive body is not recognized, " "supplying empty one"); /* * Decoding opportunity has come and gone. * Where's the result? * Try to feed with empty body, see if it eats it. */ if(prim_body_decoder(s_arg.type_descriptor, s_arg.struct_key, &ch, 0) != XPBD_BODY_CONSUMED) { /* * This decoder does not like empty stuff. */ _ASN_DECODE_FAILED; } } break; case RC_WMORE: /* * Redo the whole thing later. * We don't have a context to save intermediate parsing state. */ rc.consumed = 0; break; case RC_FAIL: rc.consumed = 0; if(s_arg.want_more) rc.code = RC_WMORE; else _ASN_DECODE_FAILED; break; } return rc; } mod_auth_gssapi-1.3.2/src/asn1c/asn_codecs_prim.h000066400000000000000000000031351266122234600217660ustar00rootroot00000000000000/*- * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef ASN_CODECS_PRIM_H #define ASN_CODECS_PRIM_H #include #ifdef __cplusplus extern "C" { #endif typedef struct ASN__PRIMITIVE_TYPE_s { uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ int size; /* Size of the buffer */ } ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ asn_struct_free_f ASN__PRIMITIVE_TYPE_free; ber_type_decoder_f ber_decode_primitive; der_type_encoder_f der_encode_primitive; /* * A callback specification for the xer_decode_primitive() function below. */ enum xer_pbd_rval { XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ XPBD_BODY_CONSUMED /* Body is recognized and consumed */ }; typedef enum xer_pbd_rval (xer_primitive_body_decoder_f) (asn_TYPE_descriptor_t *td, void *struct_ptr, const void *chunk_buf, size_t chunk_size); /* * Specific function to decode simple primitive types. * Also see xer_decode_general() in xer_decoder.h */ asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr, size_t struct_size, const char *opt_mname, const void *buf_ptr, size_t size, xer_primitive_body_decoder_f *prim_body_decoder ); #ifdef __cplusplus } #endif #endif /* ASN_CODECS_PRIM_H */ mod_auth_gssapi-1.3.2/src/asn1c/asn_internal.h000066400000000000000000000073541266122234600213220ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004, 2005, 2007 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * Declarations internally useful for the ASN.1 support code. */ #ifndef _ASN_INTERNAL_H_ #define _ASN_INTERNAL_H_ #include "asn_application.h" /* Application-visible API */ #ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ #include /* for assert() macro */ #endif #ifdef __cplusplus extern "C" { #endif /* Environment version might be used to avoid running with the old library */ #define ASN1C_ENVIRONMENT_VERSION 923 /* Compile-time version */ int get_asn1c_environment_version(void); /* Run-time version */ #define CALLOC(nmemb, size) calloc(nmemb, size) #define MALLOC(size) malloc(size) #define REALLOC(oldptr, size) realloc(oldptr, size) #define FREEMEM(ptr) free(ptr) #define asn_debug_indent 0 #define ASN_DEBUG_INDENT_ADD(i) do{}while(0) /* * A macro for debugging the ASN.1 internals. * You may enable or override it. */ #ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ #if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ #ifdef __GNUC__ #ifdef ASN_THREAD_SAFE /* Thread safety requires sacrifice in output indentation: * Retain empty definition of ASN_DEBUG_INDENT_ADD. */ #else /* !ASN_THREAD_SAFE */ #undef ASN_DEBUG_INDENT_ADD #undef asn_debug_indent int asn_debug_indent; #define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0) #endif /* ASN_THREAD_SAFE */ #define ASN_DEBUG(fmt, args...) do { \ int adi = asn_debug_indent; \ while(adi--) fprintf(stderr, " "); \ fprintf(stderr, fmt, ##args); \ fprintf(stderr, " (%s:%d)\n", \ __FILE__, __LINE__); \ } while(0) #else /* !__GNUC__ */ void ASN_DEBUG_f(const char *fmt, ...); #define ASN_DEBUG ASN_DEBUG_f #endif /* __GNUC__ */ #else /* EMIT_ASN_DEBUG != 1 */ static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } #endif /* EMIT_ASN_DEBUG */ #endif /* ASN_DEBUG */ /* * Invoke the application-supplied callback and fail, if something is wrong. */ #define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) #define _ASN_E_CALLBACK(foo) do { \ if(foo) goto cb_failed; \ } while(0) #define _ASN_CALLBACK(buf, size) \ _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) #define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) #define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) \ || __ASN_E_cbc(buf2, size2) \ || __ASN_E_cbc(buf3, size3)) #define _i_ASN_TEXT_INDENT(nl, level) do { \ int __level = (level); \ int __nl = ((nl) != 0); \ int __i; \ if(__nl) _ASN_CALLBACK("\n", 1); \ if(__level < 0) __level = 0; \ for(__i = 0; __i < __level; __i++) \ _ASN_CALLBACK(" ", 4); \ er.encoded += __nl + 4 * __level; \ } while(0) #define _i_INDENT(nl) do { \ int __i; \ if((nl) && cb("\n", 1, app_key) < 0) return -1; \ for(__i = 0; __i < ilevel; __i++) \ if(cb(" ", 4, app_key) < 0) return -1; \ } while(0) /* * Check stack against overflow, if limit is set. */ #define _ASN_DEFAULT_STACK_MAX (30000) static inline int _ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) { if(ctx && ctx->max_stack_size) { /* ctx MUST be allocated on the stack */ ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); if(usedstack > 0) usedstack = -usedstack; /* grows up! */ /* double negative required to avoid int wrap-around */ if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { ASN_DEBUG("Stack limit %ld reached", (long)ctx->max_stack_size); return -1; } } return 0; } #ifdef __cplusplus } #endif #endif /* _ASN_INTERNAL_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/asn_system.h000066400000000000000000000064401266122234600210250ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004, 2007 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * Miscellaneous system-dependent types. */ #ifndef _ASN_SYSTEM_H_ #define _ASN_SYSTEM_H_ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* For snprintf(3) */ #include /* For *alloc(3) */ #include /* For memcpy(3) */ #include /* For size_t */ #include /* For LONG_MAX */ #include /* For va_start */ #include /* for offsetof and ptrdiff_t */ #ifdef _WIN32 #include #define snprintf _snprintf #define vsnprintf _vsnprintf /* To avoid linking with ws2_32.lib, here's the definition of ntohl() */ #define sys_ntohl(l) ((((l) << 24) & 0xff000000) \ | (((l) << 8) & 0xff0000) \ | (((l) >> 8) & 0xff00) \ | ((l >> 24) & 0xff)) #ifdef _MSC_VER /* MSVS.Net */ #ifndef __cplusplus #define inline __inline #endif #ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ #define ssize_t SSIZE_T typedef char int8_t; typedef short int16_t; typedef int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #endif /* ASSUMESTDTYPES */ #define WIN32_LEAN_AND_MEAN #include #include #define isnan _isnan #define finite _finite #define copysign _copysign #define ilogb _logb #else /* !_MSC_VER */ #include #endif /* _MSC_VER */ #else /* !_WIN32 */ #if defined(__vxworks) #include #else /* !defined(__vxworks) */ #include /* C99 specifies this file */ /* * 1. Earlier FreeBSD version didn't have , * but was present. * 2. Sun Solaris requires for alloca(3), * but does not have . */ #if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) #if defined(sun) #include /* For alloca(3) */ #include /* for finite(3) */ #elif defined(__hpux) #ifdef __GNUC__ #include /* For alloca(3) */ #else /* !__GNUC__ */ #define inline #endif /* __GNUC__ */ #else #include /* SUSv2+ and C99 specify this file, for uintXX_t */ #endif /* defined(sun) */ #endif #include /* for ntohl() */ #define sys_ntohl(foo) ntohl(foo) #endif /* defined(__vxworks) */ #endif /* _WIN32 */ #if __GNUC__ >= 3 #ifndef GCC_PRINTFLIKE #define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) #endif #ifndef GCC_NOTUSED #define GCC_NOTUSED __attribute__((unused)) #endif #else #ifndef GCC_PRINTFLIKE #define GCC_PRINTFLIKE(fmt,var) /* nothing */ #endif #ifndef GCC_NOTUSED #define GCC_NOTUSED #endif #endif /* Figure out if thread safety is requested */ #if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT)) #define ASN_THREAD_SAFE #endif /* Thread safety */ #ifndef offsetof /* If not defined by */ #define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) #endif /* offsetof */ #ifndef MIN /* Suitable for comparing primitive types (integers) */ #if defined(__GNUC__) #define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ ((_a)<(_b)?(_a):(_b)); }) #else /* !__GNUC__ */ #define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ #endif /* __GNUC__ */ #endif /* MIN */ #endif /* _ASN_SYSTEM_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/ber_decoder.c000066400000000000000000000167671266122234600211050ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #undef ADVANCE #define ADVANCE(num_bytes) do { \ size_t num = num_bytes; \ ptr = ((const char *)ptr) + num; \ size -= num; \ consumed_myself += num; \ } while(0) #undef RETURN #define RETURN(_code) do { \ asn_dec_rval_t rval; \ rval.code = _code; \ if(opt_ctx) opt_ctx->step = step; /* Save context */ \ if(_code == RC_OK || opt_ctx) \ rval.consumed = consumed_myself; \ else \ rval.consumed = 0; /* Context-free */ \ return rval; \ } while(0) /* * The BER decoder of any type. */ asn_dec_rval_t ber_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr, const void *ptr, size_t size) { asn_codec_ctx_t s_codec_ctx; /* * Stack checker requires that the codec context * must be allocated on the stack. */ if(opt_codec_ctx) { if(opt_codec_ctx->max_stack_size) { s_codec_ctx = *opt_codec_ctx; opt_codec_ctx = &s_codec_ctx; } } else { /* If context is not given, be security-conscious anyway */ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; opt_codec_ctx = &s_codec_ctx; } /* * Invoke type-specific decoder. */ return type_descriptor->ber_decoder(opt_codec_ctx, type_descriptor, struct_ptr, /* Pointer to the destination structure */ ptr, size, /* Buffer and its size */ 0 /* Default tag mode is 0 */ ); } /* * Check the set of >> tags matches the definition. */ asn_dec_rval_t ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, const void *ptr, size_t size, int tag_mode, int last_tag_form, ber_tlv_len_t *last_length, int *opt_tlv_form) { ssize_t consumed_myself = 0; ssize_t tag_len; ssize_t len_len; ber_tlv_tag_t tlv_tag; ber_tlv_len_t tlv_len; ber_tlv_len_t limit_len = -1; int expect_00_terminators = 0; int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */ int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */ int tagno; /* * Make sure we didn't exceed the maximum stack size. */ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) RETURN(RC_FAIL); /* * So what does all this implicit skip stuff mean? * Imagine two types, * A ::= [5] IMPLICIT T * B ::= [2] EXPLICIT T * Where T is defined as * T ::= [4] IMPLICIT SEQUENCE { ... } * * Let's say, we are starting to decode type A, given the * following TLV stream: <5> <0>. What does this mean? * It means that the type A contains type T which is, * in turn, empty. * Remember though, that we are still in A. We cannot * just pass control to the type T decoder. Why? Because * the type T decoder expects <4> <0>, not <5> <0>. * So, we must make sure we are going to receive <5> while * still in A, then pass control to the T decoder, indicating * that the tag <4> was implicitly skipped. The decoder of T * hence will be prepared to treat <4> as valid tag, and decode * it appropriately. */ tagno = step /* Continuing where left previously */ + (tag_mode==1?-1:0) ; ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)", td->name, (long)size, tag_mode, step, tagno); /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */ if(tag_mode == 0 && tagno == td->tags_count) { /* * This must be the _untagged_ ANY type, * which outermost tag isn't known in advance. * Fetch the tag and length separately. */ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); switch(tag_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } tlv_constr = BER_TLV_CONSTRUCTED(ptr); len_len = ber_fetch_length(tlv_constr, (const char *)ptr + tag_len, size - tag_len, &tlv_len); switch(len_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } ASN_DEBUG("Advancing %ld in ANY case", (long)(tag_len + len_len)); ADVANCE(tag_len + len_len); } else { assert(tagno < td->tags_count); /* At least one loop */ } for((void)tagno; tagno < td->tags_count; tagno++, step++) { /* * Fetch and process T from TLV. */ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); ASN_DEBUG("Fetching tag from {%p,%ld}: " "len %ld, step %d, tagno %d got %s", ptr, (long)size, (long)tag_len, step, tagno, ber_tlv_tag_string(tlv_tag)); switch(tag_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } tlv_constr = BER_TLV_CONSTRUCTED(ptr); /* * If {I}, don't check anything. * If {I,B,C}, check B and C unless we're at I. */ if(tag_mode != 0 && step == 0) { /* * We don't expect tag to match here. * It's just because we don't know how the tag * is supposed to look like. */ } else { assert(tagno >= 0); /* Guaranteed by the code above */ if(tlv_tag != td->tags[tagno]) { /* * Unexpected tag. Too bad. */ ASN_DEBUG("Expected: %s, " "expectation failed (tn=%d, tm=%d)", ber_tlv_tag_string(td->tags[tagno]), tagno, tag_mode ); RETURN(RC_FAIL); } } /* * Attention: if there are more tags expected, * ensure that the current tag is presented * in constructed form (it contains other tags!). * If this one is the last one, check that the tag form * matches the one given in descriptor. */ if(tagno < (td->tags_count - 1)) { if(tlv_constr == 0) { ASN_DEBUG("tlv_constr = %d, expfail", tlv_constr); RETURN(RC_FAIL); } } else { if(last_tag_form != tlv_constr && last_tag_form != -1) { ASN_DEBUG("last_tag_form %d != %d", last_tag_form, tlv_constr); RETURN(RC_FAIL); } } /* * Fetch and process L from TLV. */ len_len = ber_fetch_length(tlv_constr, (const char *)ptr + tag_len, size - tag_len, &tlv_len); ASN_DEBUG("Fetching len = %ld", (long)len_len); switch(len_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); } /* * FIXME * As of today, the chain of tags * must either contain several indefinite length TLVs, * or several definite length ones. * No mixing is allowed. */ if(tlv_len == -1) { /* * Indefinite length. */ if(limit_len == -1) { expect_00_terminators++; } else { ASN_DEBUG("Unexpected indefinite length " "in a chain of definite lengths"); RETURN(RC_FAIL); } ADVANCE(tag_len + len_len); continue; } else { if(expect_00_terminators) { ASN_DEBUG("Unexpected definite length " "in a chain of indefinite lengths"); RETURN(RC_FAIL); } } /* * Check that multiple TLVs specify ever decreasing length, * which is consistent. */ if(limit_len == -1) { limit_len = tlv_len + tag_len + len_len; if(limit_len < 0) { /* Too great tlv_len value? */ RETURN(RC_FAIL); } } else if(limit_len != tlv_len + tag_len + len_len) { /* * Inner TLV specifies length which is inconsistent * with the outer TLV's length value. */ ASN_DEBUG("Outer TLV is %ld and inner is %ld", (long)limit_len, (long)tlv_len); RETURN(RC_FAIL); } ADVANCE(tag_len + len_len); limit_len -= (tag_len + len_len); if((ssize_t)size > limit_len) { /* * Make sure that we won't consume more bytes * from the parent frame than the inferred limit. */ size = limit_len; } } if(opt_tlv_form) *opt_tlv_form = tlv_constr; if(expect_00_terminators) *last_length = -expect_00_terminators; else *last_length = tlv_len; RETURN(RC_OK); } mod_auth_gssapi-1.3.2/src/asn1c/ber_decoder.h000066400000000000000000000037771266122234600211070ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _BER_DECODER_H_ #define _BER_DECODER_H_ #include #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ struct asn_codec_ctx_s; /* Forward declaration */ /* * The BER decoder of any type. * This function may be invoked directly from the application. * The der_encode() function (der_encoder.h) is an opposite to ber_decode(). */ asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, void **struct_ptr, /* Pointer to a target structure's pointer */ const void *buffer, /* Data to be decoded */ size_t size /* Size of that buffer */ ); /* * Type of generic function which decodes the byte stream into the structure. */ typedef asn_dec_rval_t (ber_type_decoder_f)( struct asn_codec_ctx_s *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, void **struct_ptr, const void *buf_ptr, size_t size, int tag_mode); /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ /* * Check that all tags correspond to the type definition (as given in head). * On return, last_length would contain either a non-negative length of the * value part of the last TLV, or the negative number of expected * "end of content" sequences. The number may only be negative if the * head->last_tag_form is non-zero. */ asn_dec_rval_t ber_check_tags( struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ struct asn_TYPE_descriptor_s *type_descriptor, asn_struct_ctx_t *opt_ctx, /* saved decoding context */ const void *ptr, size_t size, int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ int last_tag_form, /* {-1,0:1}: any, primitive, constr */ ber_tlv_len_t *last_length, int *opt_tlv_form /* optional tag form */ ); #ifdef __cplusplus } #endif #endif /* _BER_DECODER_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/ber_tlv_length.c000066400000000000000000000073101266122234600216260ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, ber_tlv_len_t *len_r) { const uint8_t *buf = (const uint8_t *)bufptr; unsigned oct; if(size == 0) return 0; /* Want more */ oct = *(const uint8_t *)buf; if((oct & 0x80) == 0) { /* * Short definite length. */ *len_r = oct; /* & 0x7F */ return 1; } else { ber_tlv_len_t len; size_t skipped; if(_is_constructed && oct == 0x80) { *len_r = -1; /* Indefinite length */ return 1; } if(oct == 0xff) { /* Reserved in standard for future use. */ return -1; } oct &= 0x7F; /* Leave only the 7 LS bits */ for(len = 0, buf++, skipped = 1; oct && (++skipped <= size); buf++, oct--) { len = (len << 8) | *buf; if(len < 0 || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) { /* * Too large length value. */ return -1; } } if(oct == 0) { ber_tlv_len_t lenplusepsilon = (size_t)len + 1024; /* * Here length may be very close or equal to 2G. * However, the arithmetics used in some decoders * may add some (small) quantities to the length, * to check the resulting value against some limits. * This may result in integer wrap-around, which * we try to avoid by checking it earlier here. */ if(lenplusepsilon < 0) { /* Too large length value */ return -1; } *len_r = len; return skipped; } return 0; /* Want more */ } } ssize_t ber_skip_length(asn_codec_ctx_t *opt_codec_ctx, int _is_constructed, const void *ptr, size_t size) { ber_tlv_len_t vlen; /* Length of V in TLV */ ssize_t tl; /* Length of L in TLV */ ssize_t ll; /* Length of L in TLV */ size_t skip; /* * Make sure we didn't exceed the maximum stack size. */ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) return -1; /* * Determine the size of L in TLV. */ ll = ber_fetch_length(_is_constructed, ptr, size, &vlen); if(ll <= 0) return ll; /* * Definite length. */ if(vlen >= 0) { skip = ll + vlen; if(skip > size) return 0; /* Want more */ return skip; } /* * Indefinite length! */ ASN_DEBUG("Skipping indefinite length"); for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) { ber_tlv_tag_t tag; /* Fetch the tag */ tl = ber_fetch_tag(ptr, size, &tag); if(tl <= 0) return tl; ll = ber_skip_length(opt_codec_ctx, BER_TLV_CONSTRUCTED(ptr), ((const char *)ptr) + tl, size - tl); if(ll <= 0) return ll; skip += tl + ll; /* * This may be the end of the indefinite length structure, * two consecutive 0 octets. * Check if it is true. */ if(((const uint8_t *)ptr)[0] == 0 && ((const uint8_t *)ptr)[1] == 0) return skip; ptr = ((const char *)ptr) + tl + ll; size -= tl + ll; } /* UNREACHABLE */ } size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) { size_t required_size; /* Size of len encoding */ uint8_t *buf = (uint8_t *)bufp; uint8_t *end; size_t i; if(len <= 127) { /* Encoded in 1 octet */ if(size) *buf = (uint8_t)len; return 1; } /* * Compute the size of the subsequent bytes. */ for(required_size = 1, i = 8; i < 8 * sizeof(len); i += 8) { if(len >> i) required_size++; else break; } if(size <= required_size) return required_size + 1; *buf++ = (uint8_t)(0x80 | required_size); /* Length of the encoding */ /* * Produce the len encoding, space permitting. */ end = buf + required_size; for(i -= 8; buf < end; i -= 8, buf++) *buf = (uint8_t)(len >> i); return required_size + 1; } mod_auth_gssapi-1.3.2/src/asn1c/ber_tlv_length.h000066400000000000000000000027751266122234600216450ustar00rootroot00000000000000/*- * Copyright (c) 2003 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _BER_TLV_LENGTH_H_ #define _BER_TLV_LENGTH_H_ #ifdef __cplusplus extern "C" { #endif typedef ssize_t ber_tlv_len_t; /* * This function tries to fetch the length of the BER TLV value and place it * in *len_r. * RETURN VALUES: * 0: More data expected than bufptr contains. * -1: Fatal error deciphering length. * >0: Number of bytes used from bufptr. * On return with >0, len_r is constrained as -1..MAX, where -1 mean * that the value is of indefinite length. */ ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, ber_tlv_len_t *len_r); /* * This function expects bufptr to be positioned over L in TLV. * It returns number of bytes occupied by L and V together, suitable * for skipping. The function properly handles indefinite length. * RETURN VALUES: * Standard {-1,0,>0} convention. */ ssize_t ber_skip_length( struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ int _is_constructed, const void *bufptr, size_t size); /* * This function serializes the length (L from TLV) in DER format. * It always returns number of bytes necessary to represent the length, * it is a caller's responsibility to check the return value * against the supplied buffer's size. */ size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); #ifdef __cplusplus } #endif #endif /* _BER_TLV_LENGTH_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/ber_tlv_tag.c000066400000000000000000000061561266122234600211270ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include ssize_t ber_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) { ber_tlv_tag_t val; ber_tlv_tag_t tclass; size_t skipped; if(size == 0) return 0; val = *(const uint8_t *)ptr; tclass = (val >> 6); if((val &= 0x1F) != 0x1F) { /* * Simple form: everything encoded in a single octet. * Tag Class is encoded using two least significant bits. */ *tag_r = (val << 2) | tclass; return 1; } /* * Each octet contains 7 bits of useful information. * The MSB is 0 if it is the last octet of the tag. */ for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; skipped <= size; ptr = ((const char *)ptr) + 1, skipped++) { unsigned int oct = *(const uint8_t *)ptr; if(oct & 0x80) { val = (val << 7) | (oct & 0x7F); /* * Make sure there are at least 9 bits spare * at the MS side of a value. */ if(val >> ((8 * sizeof(val)) - 9)) { /* * We would not be able to accomodate * any more tag bits. */ return -1; } } else { val = (val << 7) | oct; *tag_r = (val << 2) | tclass; return skipped; } } return 0; /* Want more */ } ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) { char buf[sizeof("[APPLICATION ]") + 32]; ssize_t ret; ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf)); if(ret >= (ssize_t)sizeof(buf) || ret < 2) { errno = EPERM; return -1; } return fwrite(buf, 1, ret, f); } ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) { char *type = 0; int ret; switch(tag & 0x3) { case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break; case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break; case ASN_TAG_CLASS_CONTEXT: type = ""; break; case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break; } ret = snprintf(buf, size, "[%s%u]", type, ((unsigned)tag) >> 2); if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */ return ret; } char * ber_tlv_tag_string(ber_tlv_tag_t tag) { static char buf[sizeof("[APPLICATION ]") + 32]; (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf)); return buf; } size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) { int tclass = BER_TAG_CLASS(tag); ber_tlv_tag_t tval = BER_TAG_VALUE(tag); uint8_t *buf = (uint8_t *)bufp; uint8_t *end; size_t required_size; size_t i; if(tval <= 30) { /* Encoded in 1 octet */ if(size) buf[0] = (tclass << 6) | tval; return 1; } else if(size) { *buf++ = (tclass << 6) | 0x1F; size--; } /* * Compute the size of the subsequent bytes. */ for(required_size = 1, i = 7; i < 8 * sizeof(tval); i += 7) { if(tval >> i) required_size++; else break; } if(size < required_size) return required_size + 1; /* * Fill in the buffer, space permitting. */ end = buf + required_size - 1; for(i -= 7; buf < end; i -= 7, buf++) *buf = 0x80 | ((tval >> i) & 0x7F); *buf = (tval & 0x7F); /* Last octet without high bit */ return required_size + 1; } mod_auth_gssapi-1.3.2/src/asn1c/ber_tlv_tag.h000066400000000000000000000034541266122234600211320ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _BER_TLV_TAG_H_ #define _BER_TLV_TAG_H_ #ifdef __cplusplus extern "C" { #endif enum asn_tag_class { ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ }; typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ /* * Tag class is encoded together with tag value for optimization purposes. */ #define BER_TAG_CLASS(tag) ((tag) & 0x3) #define BER_TAG_VALUE(tag) ((tag) >> 2) #define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) #define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) /* * Several functions for printing the TAG in the canonical form * (i.e. "[PRIVATE 0]"). * Return values correspond to their libc counterparts (if any). */ ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); char *ber_tlv_tag_string(ber_tlv_tag_t tag); /* * This function tries to fetch the tag from the input stream. * RETURN VALUES: * 0: More data expected than bufptr contains. * -1: Fatal error deciphering tag. * >0: Number of bytes used from bufptr. tag_r will contain the tag. */ ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); /* * This function serializes the tag (T from TLV) in BER format. * It always returns number of bytes necessary to represent the tag, * it is a caller's responsibility to check the return value * against the supplied buffer's size. */ size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); #ifdef __cplusplus } #endif #endif /* _BER_TLV_TAG_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/constr_SEQUENCE.c000066400000000000000000001072501266122234600214340ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* * Number of bytes left for this structure. * (ctx->left) indicates the number of bytes _transferred_ for the structure. * (size) contains the number of bytes in the buffer passed. */ #define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) /* * If the subprocessor function returns with an indication that it wants * more data, it may well be a fatal decoding problem, because the * size is constrained by the 's L, even if the buffer size allows * reading more data. * For example, consider the buffer containing the following TLVs: * ... * The TLV length clearly indicates that one byte is expected in V, but * if the V processor returns with "want more data" even if the buffer * contains way more data than the V processor have seen. */ #define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) /* * This macro "eats" the part of the buffer which is definitely "consumed", * i.e. was correctly converted into local representation or rightfully skipped. */ #undef ADVANCE #define ADVANCE(num_bytes) do { \ size_t num = num_bytes; \ ptr = ((const char *)ptr) + num; \ size -= num; \ if(ctx->left >= 0) \ ctx->left -= num; \ consumed_myself += num; \ } while(0) /* * Switch to the next phase of parsing. */ #undef NEXT_PHASE #undef PHASE_OUT #define NEXT_PHASE(ctx) do { \ ctx->phase++; \ ctx->step = 0; \ } while(0) #define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) /* * Return a standardized complex structure. */ #undef RETURN #define RETURN(_code) do { \ rval.code = _code; \ rval.consumed = consumed_myself;\ return rval; \ } while(0) /* * Check whether we are inside the extensions group. */ #define IN_EXTENSION_GROUP(specs, memb_idx) \ ( ((memb_idx) > (specs)->ext_after) \ &&((memb_idx) < (specs)->ext_before)) /* * Tags are canonically sorted in the tag2element map. */ static int _t2e_cmp(const void *ap, const void *bp) { const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; int a_class = BER_TAG_CLASS(a->el_tag); int b_class = BER_TAG_CLASS(b->el_tag); if(a_class == b_class) { ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); if(a_value == b_value) { if(a->el_no > b->el_no) return 1; /* * Important: we do not check * for a->el_no <= b->el_no! */ return 0; } else if(a_value < b_value) return -1; else return 1; } else if(a_class < b_class) { return -1; } else { return 1; } } /* * The decoder of the SEQUENCE type. */ asn_dec_rval_t SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **struct_ptr, const void *ptr, size_t size, int tag_mode) { /* * Bring closer parts of structure description. */ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; asn_TYPE_member_t *elements = td->elements; /* * Parts of the structure being constructed. */ void *st = *struct_ptr; /* Target structure. */ asn_struct_ctx_t *ctx; /* Decoder context */ ber_tlv_tag_t tlv_tag; /* T from TLV */ asn_dec_rval_t rval; /* Return code from subparsers */ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ int edx; /* SEQUENCE element's index */ ASN_DEBUG("Decoding %s as SEQUENCE", td->name); /* * Create the target structure if it is not present already. */ if(st == 0) { st = *struct_ptr = CALLOC(1, specs->struct_size); if(st == 0) { RETURN(RC_FAIL); } } /* * Restore parsing context. */ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); /* * Start to parse where left previously */ switch(ctx->phase) { case 0: /* * PHASE 0. * Check that the set of tags associated with given structure * perfectly fits our expectations. */ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, tag_mode, 1, &ctx->left, 0); if(rval.code != RC_OK) { ASN_DEBUG("%s tagging check failed: %d", td->name, rval.code); return rval; } if(ctx->left >= 0) ctx->left += rval.consumed; /* ?Substracted below! */ ADVANCE(rval.consumed); NEXT_PHASE(ctx); ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", (long)ctx->left, (long)size); /* Fall through */ case 1: /* * PHASE 1. * From the place where we've left it previously, * try to decode the next member from the list of * this structure's elements. * (ctx->step) stores the member being processed * between invocations and the microphase {0,1} of parsing * that member: * step = ( * 2 + ). */ for(edx = (ctx->step >> 1); edx < td->elements_count; edx++, ctx->step = (ctx->step & ~1) + 2) { void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ ssize_t tag_len; /* Length of TLV's T */ int opt_edx_end; /* Next non-optional element */ int use_bsearch; int n; if(ctx->step & 1) goto microphase2; /* * MICROPHASE 1: Synchronize decoding. */ ASN_DEBUG("In %s SEQUENCE left %d, edx=%d flags=%d" " opt=%d ec=%d", td->name, (int)ctx->left, edx, elements[edx].flags, elements[edx].optional, td->elements_count); if(ctx->left == 0 /* No more stuff is expected */ && ( /* Explicit OPTIONAL specification reaches the end */ (edx + elements[edx].optional == td->elements_count) || /* All extensions are optional */ (IN_EXTENSION_GROUP(specs, edx) && specs->ext_before > td->elements_count) ) ) { ASN_DEBUG("End of SEQUENCE %s", td->name); /* * Found the legitimate end of the structure. */ PHASE_OUT(ctx); RETURN(RC_OK); } /* * Fetch the T from TLV. */ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); ASN_DEBUG("Current tag in %s SEQUENCE for element %d " "(%s) is %s encoded in %d bytes, of frame %ld", td->name, edx, elements[edx].name, ber_tlv_tag_string(tlv_tag), (int)tag_len, (long)LEFT); switch(tag_len) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { if(LEFT < 2) { if(SIZE_VIOLATION) RETURN(RC_FAIL); else RETURN(RC_WMORE); } else if(((const uint8_t *)ptr)[1] == 0) { ASN_DEBUG("edx = %d, opt = %d, ec=%d", edx, elements[edx].optional, td->elements_count); if((edx + elements[edx].optional == td->elements_count) || (IN_EXTENSION_GROUP(specs, edx) && specs->ext_before > td->elements_count)) { /* * Yeah, baby! Found the terminator * of the indefinite length structure. */ /* * Proceed to the canonical * finalization function. * No advancing is necessary. */ goto phase3; } } } /* * Find the next available type with this tag. */ use_bsearch = 0; opt_edx_end = edx + elements[edx].optional + 1; if(opt_edx_end > td->elements_count) opt_edx_end = td->elements_count; /* Cap */ else if(opt_edx_end - edx > 8) { /* Limit the scope of linear search... */ opt_edx_end = edx + 8; use_bsearch = 1; /* ... and resort to bsearch() */ } for(n = edx; n < opt_edx_end; n++) { if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) { /* * Found element corresponding to the tag * being looked at. * Reposition over the right element. */ edx = n; ctx->step = 1 + 2 * edx; /* Remember! */ goto microphase2; } else if(elements[n].flags & ATF_OPEN_TYPE) { /* * This is the ANY type, which may bear * any flag whatsoever. */ edx = n; ctx->step = 1 + 2 * edx; /* Remember! */ goto microphase2; } else if(elements[n].tag == (ber_tlv_tag_t)-1) { use_bsearch = 1; break; } } if(use_bsearch) { /* * Resort to a binary search over * sorted array of tags. */ asn_TYPE_tag2member_t *t2m; asn_TYPE_tag2member_t key; key.el_tag = tlv_tag; key.el_no = edx; t2m = (asn_TYPE_tag2member_t *)bsearch(&key, specs->tag2el, specs->tag2el_count, sizeof(specs->tag2el[0]), _t2e_cmp); if(t2m) { asn_TYPE_tag2member_t *best = 0; asn_TYPE_tag2member_t *t2m_f, *t2m_l; int edx_max = edx + elements[edx].optional; /* * Rewind to the first element with that tag, * `cause bsearch() does not guarantee order. */ t2m_f = t2m + t2m->toff_first; t2m_l = t2m + t2m->toff_last; for(t2m = t2m_f; t2m <= t2m_l; t2m++) { if(t2m->el_no > edx_max) break; if(t2m->el_no < edx) continue; best = t2m; } if(best) { edx = best->el_no; ctx->step = 1 + 2 * edx; goto microphase2; } } n = opt_edx_end; } if(n == opt_edx_end) { /* * If tag is unknown, it may be either * an unknown (thus, incorrect) tag, * or an extension (...), * or an end of the indefinite-length structure. */ if(!IN_EXTENSION_GROUP(specs, edx + elements[edx].optional)) { ASN_DEBUG("Unexpected tag %s (at %d)", ber_tlv_tag_string(tlv_tag), edx); ASN_DEBUG("Expected tag %s (%s)%s", ber_tlv_tag_string(elements[edx].tag), elements[edx].name, elements[edx].optional ?" or alternatives":""); RETURN(RC_FAIL); } else { /* Skip this tag */ ssize_t skip; edx += elements[edx].optional; ASN_DEBUG("Skipping unexpected %s (at %d)", ber_tlv_tag_string(tlv_tag), edx); skip = ber_skip_length(opt_codec_ctx, BER_TLV_CONSTRUCTED(ptr), (const char *)ptr + tag_len, LEFT - tag_len); ASN_DEBUG("Skip length %d in %s", (int)skip, td->name); switch(skip) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } ADVANCE(skip + tag_len); ctx->step -= 2; edx--; continue; /* Try again with the next tag */ } } /* * MICROPHASE 2: Invoke the member-specific decoder. */ ctx->step |= 1; /* Confirm entering next microphase */ microphase2: ASN_DEBUG("Inside SEQUENCE %s MF2", td->name); /* * Compute the position of the member inside a structure, * and also a type of containment (it may be contained * as pointer or using inline inclusion). */ if(elements[edx].flags & ATF_POINTER) { /* Member is a pointer to another structure */ memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset); } else { /* * A pointer to a pointer * holding the start of the structure */ memb_ptr = (char *)st + elements[edx].memb_offset; memb_ptr2 = &memb_ptr; } /* * Invoke the member fetch routine according to member's type */ rval = elements[edx].type->ber_decoder(opt_codec_ctx, elements[edx].type, memb_ptr2, ptr, LEFT, elements[edx].tag_mode); ASN_DEBUG("In %s SEQUENCE decoded %d %s of %d " "in %d bytes rval.code %d, size=%d", td->name, edx, elements[edx].type->name, (int)LEFT, (int)rval.consumed, rval.code, (int)size); switch(rval.code) { case RC_OK: break; case RC_WMORE: /* More data expected */ if(!SIZE_VIOLATION) { ADVANCE(rval.consumed); RETURN(RC_WMORE); } ASN_DEBUG("Size violation (c->l=%ld <= s=%ld)", (long)ctx->left, (long)size); /* Fall through */ case RC_FAIL: /* Fatal error */ RETURN(RC_FAIL); } /* switch(rval) */ ADVANCE(rval.consumed); } /* for(all structure members) */ phase3: ctx->phase = 3; case 3: /* 00 and other tags expected */ case 4: /* only 00's expected */ ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld", td->name, (long)ctx->left, (long)size); /* * Skip everything until the end of the SEQUENCE. */ while(ctx->left) { ssize_t tl, ll; tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); switch(tl) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } /* * If expected <0><0>... */ if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { if(LEFT < 2) { if(SIZE_VIOLATION) RETURN(RC_FAIL); else RETURN(RC_WMORE); } else if(((const uint8_t *)ptr)[1] == 0) { /* * Correctly finished with <0><0>. */ ADVANCE(2); ctx->left++; ctx->phase = 4; continue; } } if(!IN_EXTENSION_GROUP(specs, td->elements_count) || ctx->phase == 4) { ASN_DEBUG("Unexpected continuation " "of a non-extensible type " "%s (SEQUENCE): %s", td->name, ber_tlv_tag_string(tlv_tag)); RETURN(RC_FAIL); } ll = ber_skip_length(opt_codec_ctx, BER_TLV_CONSTRUCTED(ptr), (const char *)ptr + tl, LEFT - tl); switch(ll) { case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); /* Fall through */ case -1: RETURN(RC_FAIL); } ADVANCE(tl + ll); } PHASE_OUT(ctx); } RETURN(RC_OK); } /* * The DER encoder of the SEQUENCE type. */ asn_enc_rval_t SEQUENCE_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) { size_t computed_size = 0; asn_enc_rval_t erval; ssize_t ret; int edx; ASN_DEBUG("%s %s as SEQUENCE", cb?"Encoding":"Estimating", td->name); /* * Gather the length of the underlying members sequence. */ for(edx = 0; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; void *memb_ptr; if(elm->flags & ATF_POINTER) { memb_ptr = *(void **)((char *)sptr + elm->memb_offset); if(!memb_ptr) { if(elm->optional) continue; /* Mandatory element is missing */ _ASN_ENCODE_FAILED; } } else { memb_ptr = (void *)((char *)sptr + elm->memb_offset); } erval = elm->type->der_encoder(elm->type, memb_ptr, elm->tag_mode, elm->tag, 0, 0); if(erval.encoded == -1) return erval; computed_size += erval.encoded; ASN_DEBUG("Member %d %s estimated %ld bytes", edx, elm->name, (long)erval.encoded); } /* * Encode the TLV for the sequence itself. */ ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size); if(ret == -1) _ASN_ENCODE_FAILED; erval.encoded = computed_size + ret; if(!cb) _ASN_ENCODED_OK(erval); /* * Encode all members. */ for(edx = 0; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; asn_enc_rval_t tmperval; void *memb_ptr; if(elm->flags & ATF_POINTER) { memb_ptr = *(void **)((char *)sptr + elm->memb_offset); if(!memb_ptr) continue; } else { memb_ptr = (void *)((char *)sptr + elm->memb_offset); } tmperval = elm->type->der_encoder(elm->type, memb_ptr, elm->tag_mode, elm->tag, cb, app_key); if(tmperval.encoded == -1) return tmperval; computed_size -= tmperval.encoded; ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %ld bytes", edx, elm->name, td->name, (long)tmperval.encoded); } if(computed_size != 0) /* * Encoded size is not equal to the computed size. */ _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(erval); } #undef XER_ADVANCE #define XER_ADVANCE(num_bytes) do { \ size_t num = num_bytes; \ buf_ptr = ((const char *)buf_ptr) + num;\ size -= num; \ consumed_myself += num; \ } while(0) /* * Decode the XER (XML) data. */ asn_dec_rval_t SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **struct_ptr, const char *opt_mname, const void *buf_ptr, size_t size) { /* * Bring closer parts of structure description. */ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; asn_TYPE_member_t *elements = td->elements; const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; /* * ... and parts of the structure being constructed. */ void *st = *struct_ptr; /* Target structure. */ asn_struct_ctx_t *ctx; /* Decoder context */ asn_dec_rval_t rval; /* Return value from a decoder */ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ int edx; /* Element index */ int edx_end; /* * Create the target structure if it is not present already. */ if(st == 0) { st = *struct_ptr = CALLOC(1, specs->struct_size); if(st == 0) RETURN(RC_FAIL); } /* * Restore parsing context. */ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); /* * Phases of XER/XML processing: * Phase 0: Check that the opening tag matches our expectations. * Phase 1: Processing body and reacting on closing tag. * Phase 2: Processing inner type. * Phase 3: Skipping unknown extensions. * Phase 4: PHASED OUT */ for(edx = ctx->step; ctx->phase <= 3;) { pxer_chunk_type_e ch_type; /* XER chunk type */ ssize_t ch_size; /* Chunk size */ xer_check_tag_e tcv; /* Tag check value */ asn_TYPE_member_t *elm; int n; /* * Go inside the inner member of a sequence. */ if(ctx->phase == 2) { asn_dec_rval_t tmprval; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ elm = &td->elements[edx]; if(elm->flags & ATF_POINTER) { /* Member is a pointer to another structure */ memb_ptr2 = (void **)((char *)st + elm->memb_offset); } else { memb_ptr = (char *)st + elm->memb_offset; memb_ptr2 = &memb_ptr; } /* Invoke the inner type decoder, m.b. multiple times */ tmprval = elm->type->xer_decoder(opt_codec_ctx, elm->type, memb_ptr2, elm->name, buf_ptr, size); XER_ADVANCE(tmprval.consumed); if(tmprval.code != RC_OK) RETURN(tmprval.code); ctx->phase = 1; /* Back to body processing */ ctx->step = ++edx; ASN_DEBUG("XER/SEQUENCE phase => %d, step => %d", ctx->phase, ctx->step); /* Fall through */ } /* * Get the next part of the XML stream. */ ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type); switch(ch_size) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); default: switch(ch_type) { case PXER_COMMENT: /* Got XML comment */ case PXER_TEXT: /* Ignore free-standing text */ XER_ADVANCE(ch_size); /* Skip silently */ continue; case PXER_TAG: break; /* Check the rest down there */ } } tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]", tcv, ctx->phase, xml_tag); /* Skip the extensions section */ if(ctx->phase == 3) { switch(xer_skip_unknown(tcv, &ctx->left)) { case -1: ctx->phase = 4; RETURN(RC_FAIL); case 0: XER_ADVANCE(ch_size); continue; case 1: XER_ADVANCE(ch_size); ctx->phase = 1; continue; case 2: ctx->phase = 1; break; } } switch(tcv) { case XCT_CLOSING: if(ctx->phase == 0) break; ctx->phase = 0; /* Fall through */ case XCT_BOTH: if(ctx->phase == 0) { if(edx >= td->elements_count || /* Explicit OPTIONAL specs reaches the end */ (edx + elements[edx].optional == td->elements_count) || /* All extensions are optional */ (IN_EXTENSION_GROUP(specs, edx) && specs->ext_before > td->elements_count) ) { XER_ADVANCE(ch_size); ctx->phase = 4; /* Phase out */ RETURN(RC_OK); } else { ASN_DEBUG("Premature end of XER SEQUENCE"); RETURN(RC_FAIL); } } /* Fall through */ case XCT_OPENING: if(ctx->phase == 0) { XER_ADVANCE(ch_size); ctx->phase = 1; /* Processing body phase */ continue; } /* Fall through */ case XCT_UNKNOWN_OP: case XCT_UNKNOWN_BO: ASN_DEBUG("XER/SEQUENCE: tcv=%d, ph=%d, edx=%d", tcv, ctx->phase, edx); if(ctx->phase != 1) { break; /* Really unexpected */ } if(edx < td->elements_count) { /* * Search which member corresponds to this tag. */ edx_end = edx + elements[edx].optional + 1; if(edx_end > td->elements_count) edx_end = td->elements_count; for(n = edx; n < edx_end; n++) { elm = &td->elements[n]; tcv = xer_check_tag(buf_ptr, ch_size, elm->name); switch(tcv) { case XCT_BOTH: case XCT_OPENING: /* * Process this member. */ ctx->step = edx = n; ctx->phase = 2; break; case XCT_UNKNOWN_OP: case XCT_UNKNOWN_BO: continue; default: n = edx_end; break; /* Phase out */ } break; } if(n != edx_end) continue; } else { ASN_DEBUG("Out of defined members: %d/%d", edx, td->elements_count); } /* It is expected extension */ if(IN_EXTENSION_GROUP(specs, edx + (edx < td->elements_count ? elements[edx].optional : 0))) { ASN_DEBUG("Got anticipated extension at %d", edx); /* * Check for (XCT_BOTH or XCT_UNKNOWN_BO) * By using a mask. Only record a pure * tags. */ if(tcv & XCT_CLOSING) { /* Found without body */ } else { ctx->left = 1; ctx->phase = 3; /* Skip ...'s */ } XER_ADVANCE(ch_size); continue; } /* Fall through */ default: break; } ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]", size>0?((const char *)buf_ptr)[0]:'.', size>1?((const char *)buf_ptr)[1]:'.', size>2?((const char *)buf_ptr)[2]:'.', size>3?((const char *)buf_ptr)[3]:'.', size>4?((const char *)buf_ptr)[4]:'.', size>5?((const char *)buf_ptr)[5]:'.'); break; } ctx->phase = 4; /* "Phase out" on hard failure */ RETURN(RC_FAIL); } asn_enc_rval_t SEQUENCE_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) { asn_enc_rval_t er; int xcan = (flags & XER_F_CANONICAL); int edx; if(!sptr) _ASN_ENCODE_FAILED; er.encoded = 0; for(edx = 0; edx < td->elements_count; edx++) { asn_enc_rval_t tmper; asn_TYPE_member_t *elm = &td->elements[edx]; void *memb_ptr; const char *mname = elm->name; unsigned int mlen = strlen(mname); if(elm->flags & ATF_POINTER) { memb_ptr = *(void **)((char *)sptr + elm->memb_offset); if(!memb_ptr) { if(elm->optional) continue; /* Mandatory element is missing */ _ASN_ENCODE_FAILED; } } else { memb_ptr = (void *)((char *)sptr + elm->memb_offset); } if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); /* Print the member itself */ tmper = elm->type->xer_encoder(elm->type, memb_ptr, ilevel + 1, flags, cb, app_key); if(tmper.encoded == -1) return tmper; _ASN_CALLBACK3("", 1); er.encoded += 5 + (2 * mlen) + tmper.encoded; } if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); _ASN_ENCODED_OK(er); cb_failed: _ASN_ENCODE_FAILED; } int SEQUENCE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { int edx; int ret; if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; /* Dump preamble */ if(cb(td->name, strlen(td->name), app_key) < 0 || cb(" ::= {", 6, app_key) < 0) return -1; for(edx = 0; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; const void *memb_ptr; if(elm->flags & ATF_POINTER) { memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); if(!memb_ptr) { if(elm->optional) continue; /* Print line */ /* Fall through */ } } else { memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); } /* Indentation */ _i_INDENT(1); /* Print the member's name and stuff */ if(cb(elm->name, strlen(elm->name), app_key) < 0 || cb(": ", 2, app_key) < 0) return -1; /* Print the member itself */ ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 1, cb, app_key); if(ret) return ret; } ilevel--; _i_INDENT(1); return (cb("}", 1, app_key) < 0) ? -1 : 0; } void SEQUENCE_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { int edx; if(!td || !sptr) return; ASN_DEBUG("Freeing %s as SEQUENCE", td->name); for(edx = 0; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; void *memb_ptr; if(elm->flags & ATF_POINTER) { memb_ptr = *(void **)((char *)sptr + elm->memb_offset); if(memb_ptr) ASN_STRUCT_FREE(*elm->type, memb_ptr); } else { memb_ptr = (void *)((char *)sptr + elm->memb_offset); ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); } } if(!contents_only) { FREEMEM(sptr); } } int SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, asn_app_constraint_failed_f *ctfailcb, void *app_key) { int edx; if(!sptr) { _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; } /* * Iterate over structure members and check their validity. */ for(edx = 0; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; const void *memb_ptr; if(elm->flags & ATF_POINTER) { memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); if(!memb_ptr) { if(elm->optional) continue; _ASN_CTFAIL(app_key, td, sptr, "%s: mandatory element %s absent (%s:%d)", td->name, elm->name, __FILE__, __LINE__); return -1; } } else { memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); } if(elm->memb_constraints) { int ret = elm->memb_constraints(elm->type, memb_ptr, ctfailcb, app_key); if(ret) return ret; } else { int ret = elm->type->check_constraints(elm->type, memb_ptr, ctfailcb, app_key); if(ret) return ret; /* * Cannot inherit it earlier: * need to make sure we get the updated version. */ elm->memb_constraints = elm->type->check_constraints; } } return 0; } asn_dec_rval_t SEQUENCE_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_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; void *st = *sptr; /* Target structure. */ int extpresent; /* Extension additions are present */ uint8_t *opres; /* Presence of optional root members */ asn_per_data_t opmd; asn_dec_rval_t rv; int edx; (void)constraints; if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) _ASN_DECODE_FAILED; if(!st) { st = *sptr = CALLOC(1, specs->struct_size); if(!st) _ASN_DECODE_FAILED; } ASN_DEBUG("Decoding %s as SEQUENCE (UPER)", td->name); /* Handle extensions */ if(specs->ext_before >= 0) { extpresent = per_get_few_bits(pd, 1); if(extpresent < 0) _ASN_DECODE_STARVED; } else { extpresent = 0; } /* Prepare a place and read-in the presence bitmap */ memset(&opmd, 0, sizeof(opmd)); if(specs->roms_count) { opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); if(!opres) _ASN_DECODE_FAILED; /* Get the presence map */ if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { FREEMEM(opres); _ASN_DECODE_STARVED; } opmd.buffer = opres; opmd.nbits = specs->roms_count; ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", td->name, specs->roms_count, *opres); } else { opres = 0; } /* * Get the sequence ROOT elements. */ for(edx = 0; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ if(IN_EXTENSION_GROUP(specs, edx)) continue; /* Fetch the pointer to this member */ if(elm->flags & ATF_POINTER) { memb_ptr2 = (void **)((char *)st + elm->memb_offset); } else { memb_ptr = (char *)st + elm->memb_offset; memb_ptr2 = &memb_ptr; } /* Deal with optionality */ if(elm->optional) { int present = per_get_few_bits(&opmd, 1); ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", td->name, elm->name, present, (int)opmd.nboff, (int)opmd.nbits); if(present == 0) { /* This element is not present */ if(elm->default_value) { /* Fill-in DEFAULT */ if(elm->default_value(1, memb_ptr2)) { FREEMEM(opres); _ASN_DECODE_FAILED; } ASN_DEBUG("Filled-in default"); } /* The member is just not present */ continue; } /* Fall through */ } /* Fetch the member from the stream */ ASN_DEBUG("Decoding member %s in %s", elm->name, td->name); rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, elm->per_constraints, memb_ptr2, pd); if(rv.code != RC_OK) { ASN_DEBUG("Failed decode %s in %s", elm->name, td->name); FREEMEM(opres); return rv; } } /* Optionality map is not needed anymore */ FREEMEM(opres); /* * Deal with extensions. */ if(extpresent) { ssize_t bmlength; uint8_t *epres; /* Presence of extension members */ asn_per_data_t epmd; bmlength = uper_get_nslength(pd); if(bmlength < 0) _ASN_DECODE_STARVED; ASN_DEBUG("Extensions %ld present in %s", (long)bmlength, td->name); epres = (uint8_t *)MALLOC((bmlength + 15) >> 3); if(!epres) _ASN_DECODE_STARVED; /* Get the extensions map */ if(per_get_many_bits(pd, epres, 0, bmlength)) _ASN_DECODE_STARVED; memset(&epmd, 0, sizeof(epmd)); epmd.buffer = epres; epmd.nbits = bmlength; ASN_DEBUG("Read in extensions bitmap for %s of %ld bits (%x..)", td->name, (long)bmlength, *epres); /* Go over extensions and read them in */ for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ int present; if(!IN_EXTENSION_GROUP(specs, edx)) { ASN_DEBUG("%d is not extension", edx); continue; } /* Fetch the pointer to this member */ if(elm->flags & ATF_POINTER) { memb_ptr2 = (void **)((char *)st + elm->memb_offset); } else { memb_ptr = (void *)((char *)st + elm->memb_offset); memb_ptr2 = &memb_ptr; } present = per_get_few_bits(&epmd, 1); if(present <= 0) { if(present < 0) break; /* No more extensions */ continue; } ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, *memb_ptr2); rv = uper_open_type_get(opt_codec_ctx, elm->type, elm->per_constraints, memb_ptr2, pd); if(rv.code != RC_OK) { FREEMEM(epres); return rv; } } /* Skip over overflow extensions which aren't present * in this system's version of the protocol */ for(;;) { ASN_DEBUG("Getting overflow extensions"); switch(per_get_few_bits(&epmd, 1)) { case -1: break; case 0: continue; default: if(uper_open_type_skip(opt_codec_ctx, pd)) { FREEMEM(epres); _ASN_DECODE_STARVED; } } break; } FREEMEM(epres); } /* Fill DEFAULT members in extensions */ for(edx = specs->roms_count; edx < specs->roms_count + specs->aoms_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; void **memb_ptr2; /* Pointer to member pointer */ if(!elm->default_value) continue; /* Fetch the pointer to this member */ if(elm->flags & ATF_POINTER) { memb_ptr2 = (void **)((char *)st + elm->memb_offset); if(*memb_ptr2) continue; } else { continue; /* Extensions are all optionals */ } /* Set default value */ if(elm->default_value(1, memb_ptr2)) { _ASN_DECODE_FAILED; } } rv.consumed = 0; rv.code = RC_OK; return rv; } static int SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr, asn_per_outp_t *po1, asn_per_outp_t *po2) { asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; int exts_present = 0; int exts_count = 0; int edx; if(specs->ext_before < 0) return 0; /* Find out which extensions are present */ for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ int present; if(!IN_EXTENSION_GROUP(specs, edx)) { ASN_DEBUG("%s (@%d) is not extension", elm->type->name, edx); continue; } /* Fetch the pointer to this member */ if(elm->flags & ATF_POINTER) { memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); present = (*memb_ptr2 != 0); } else { memb_ptr = (void *)((char *)sptr + elm->memb_offset); memb_ptr2 = &memb_ptr; present = 1; } ASN_DEBUG("checking %s (@%d) present => %d", elm->type->name, edx, present); exts_count++; exts_present += present; /* Encode as presence marker */ if(po1 && per_put_few_bits(po1, present, 1)) return -1; /* Encode as open type field */ if(po2 && present && uper_open_type_put(elm->type, elm->per_constraints, *memb_ptr2, po2)) return -1; } return exts_present ? exts_count : 0; } asn_enc_rval_t SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; asn_enc_rval_t er; int n_extensions; int edx; int i; (void)constraints; if(!sptr) _ASN_ENCODE_FAILED; er.encoded = 0; ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); /* * X.691#18.1 Whether structure is extensible * and whether to encode extensions */ if(specs->ext_before >= 0) { n_extensions = SEQUENCE_handle_extensions(td, sptr, 0, 0); per_put_few_bits(po, n_extensions ? 1 : 0, 1); } else { n_extensions = 0; /* There are no extensions to encode */ } /* Encode a presence bitmap */ for(i = 0; i < specs->roms_count; i++) { asn_TYPE_member_t *elm; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ int present; edx = specs->oms[i]; elm = &td->elements[edx]; /* Fetch the pointer to this member */ if(elm->flags & ATF_POINTER) { memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); present = (*memb_ptr2 != 0); } else { memb_ptr = (void *)((char *)sptr + elm->memb_offset); memb_ptr2 = &memb_ptr; present = 1; } /* Eliminate default values */ if(present && elm->default_value && elm->default_value(0, memb_ptr2) == 1) present = 0; ASN_DEBUG("Element %s %s %s->%s is %s", elm->flags & ATF_POINTER ? "ptr" : "inline", elm->default_value ? "def" : "wtv", td->name, elm->name, present ? "present" : "absent"); if(per_put_few_bits(po, present, 1)) _ASN_ENCODE_FAILED; } /* * Encode the sequence ROOT elements. */ ASN_DEBUG("ext_after = %d, ec = %d, eb = %d", specs->ext_after, td->elements_count, specs->ext_before); for(edx = 0; edx < ((specs->ext_after < 0) ? td->elements_count : specs->ext_before - 1); edx++) { asn_TYPE_member_t *elm = &td->elements[edx]; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ if(IN_EXTENSION_GROUP(specs, edx)) continue; ASN_DEBUG("About to encode %s", elm->type->name); /* Fetch the pointer to this member */ if(elm->flags & ATF_POINTER) { memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); if(!*memb_ptr2) { ASN_DEBUG("Element %s %d not present", elm->name, edx); if(elm->optional) continue; /* Mandatory element is missing */ _ASN_ENCODE_FAILED; } } else { memb_ptr = (void *)((char *)sptr + elm->memb_offset); memb_ptr2 = &memb_ptr; } /* Eliminate default values */ if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) continue; ASN_DEBUG("Encoding %s->%s", td->name, elm->name); er = elm->type->uper_encoder(elm->type, elm->per_constraints, *memb_ptr2, po); if(er.encoded == -1) return er; } /* No extensions to encode */ if(!n_extensions) _ASN_ENCODED_OK(er); ASN_DEBUG("Length of %d bit-map", n_extensions); /* #18.8. Write down the presence bit-map length. */ if(uper_put_nslength(po, n_extensions)) _ASN_ENCODE_FAILED; ASN_DEBUG("Bit-map of %d elements", n_extensions); /* #18.7. Encoding the extensions presence bit-map. */ /* TODO: act upon NOTE in #18.7 for canonical PER */ if(SEQUENCE_handle_extensions(td, sptr, po, 0) != n_extensions) _ASN_ENCODE_FAILED; ASN_DEBUG("Writing %d extensions", n_extensions); /* #18.9. Encode extensions as open type fields. */ if(SEQUENCE_handle_extensions(td, sptr, 0, po) != n_extensions) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); } mod_auth_gssapi-1.3.2/src/asn1c/constr_SEQUENCE.h000066400000000000000000000027641266122234600214450ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _CONSTR_SEQUENCE_H_ #define _CONSTR_SEQUENCE_H_ #include #ifdef __cplusplus extern "C" { #endif typedef struct asn_SEQUENCE_specifics_s { /* * Target structure description. */ int struct_size; /* Size of the target structure. */ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ /* * Tags to members mapping table (sorted). */ asn_TYPE_tag2member_t *tag2el; int tag2el_count; /* * Optional members of the extensions root (roms) or additions (aoms). * Meaningful for PER. */ int *oms; /* Optional MemberS */ int roms_count; /* Root optional members count */ int aoms_count; /* Additions optional members count */ /* * Description of an extensions group. */ int ext_after; /* Extensions start after this member */ int ext_before; /* Extensions stop before this member */ } asn_SEQUENCE_specifics_t; /* * A set specialized functions dealing with the SEQUENCE type. */ asn_struct_free_f SEQUENCE_free; asn_struct_print_f SEQUENCE_print; asn_constr_check_f SEQUENCE_constraint; ber_type_decoder_f SEQUENCE_decode_ber; der_type_encoder_f SEQUENCE_encode_der; xer_type_decoder_f SEQUENCE_decode_xer; xer_type_encoder_f SEQUENCE_encode_xer; per_type_decoder_f SEQUENCE_decode_uper; per_type_encoder_f SEQUENCE_encode_uper; #ifdef __cplusplus } #endif #endif /* _CONSTR_SEQUENCE_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/constr_TYPE.c000066400000000000000000000033421266122234600210020ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* * Version of the ASN.1 infrastructure shipped with compiler. */ int get_asn1c_environment_version() { return ASN1C_ENVIRONMENT_VERSION; } static asn_app_consume_bytes_f _print2fp; /* * Return the outmost tag of the type. */ ber_tlv_tag_t asn_TYPE_outmost_tag(asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) { if(tag_mode) return tag; if(type_descriptor->tags_count) return type_descriptor->tags[0]; return type_descriptor->outmost_tag(type_descriptor, struct_ptr, 0, 0); } /* * Print the target language's structure in human readable form. */ int asn_fprint(FILE *stream, asn_TYPE_descriptor_t *td, const void *struct_ptr) { if(!stream) stream = stdout; if(!td || !struct_ptr) { errno = EINVAL; return -1; } /* Invoke type-specific printer */ if(td->print_struct(td, struct_ptr, 1, _print2fp, stream)) return -1; /* Terminate the output */ if(_print2fp("\n", 1, stream)) return -1; return fflush(stream); } /* Dump the data into the specified stdio stream */ static int _print2fp(const void *buffer, size_t size, void *app_key) { FILE *stream = (FILE *)app_key; if(fwrite(buffer, 1, size, stream) != size) return -1; return 0; } /* * Some compilers do not support variable args macros. * This function is a replacement of ASN_DEBUG() macro. */ void ASN_DEBUG_f(const char *fmt, ...); void ASN_DEBUG_f(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); } mod_auth_gssapi-1.3.2/src/asn1c/constr_TYPE.h000066400000000000000000000150561266122234600210140ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* * This file contains the declaration structure called "ASN.1 Type Definition", * which holds all information necessary for encoding and decoding routines. * This structure even contains pointer to these encoding and decoding routines * for each defined ASN.1 type. */ #ifndef _CONSTR_TYPE_H_ #define _CONSTR_TYPE_H_ #include #include #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ struct asn_TYPE_member_s; /* Forward declaration */ /* * This type provides the context information for various ASN.1 routines, * primarily ones doing decoding. A member _asn_ctx of this type must be * included into certain target language's structures, such as compound types. */ typedef struct asn_struct_ctx_s { short phase; /* Decoding phase */ short step; /* Elementary step of a phase */ int context; /* Other context information */ void *ptr; /* Decoder-specific stuff (stack elements) */ ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ } asn_struct_ctx_t; #include /* Basic Encoding Rules decoder */ #include /* Distinguished Encoding Rules encoder */ #include /* Decoder of XER (XML, text) */ #include /* Encoder into XER (XML, text) */ #include /* Packet Encoding Rules decoder */ #include /* Packet Encoding Rules encoder */ #include /* Subtype constraints support */ /* * Free the structure according to its specification. * If (free_contents_only) is set, the wrapper structure itself (struct_ptr) * will not be freed. (It may be useful in case the structure is allocated * statically or arranged on the stack, yet its elements are allocated * dynamically.) */ typedef void (asn_struct_free_f)( struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, int free_contents_only); #define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF),ptr,0) #define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ (asn_DEF).free_struct(&(asn_DEF),ptr,1) /* * Print the structure according to its specification. */ typedef int (asn_struct_print_f)( struct asn_TYPE_descriptor_s *type_descriptor, const void *struct_ptr, int level, /* Indentation level */ asn_app_consume_bytes_f *callback, void *app_key); /* * Return the outmost tag of the type. * If the type is untagged CHOICE, the dynamic operation is performed. * NOTE: This function pointer type is only useful internally. * Do not use it in your application. */ typedef ber_tlv_tag_t (asn_outmost_tag_f)( struct asn_TYPE_descriptor_s *type_descriptor, const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); /* The instance of the above function type; used internally. */ asn_outmost_tag_f asn_TYPE_outmost_tag; /* * The definitive description of the destination language's structure. */ typedef struct asn_TYPE_descriptor_s { char *name; /* A name of the ASN.1 type. "" in some cases. */ char *xml_tag; /* Name used in XML tag */ /* * Generalized functions for dealing with the specific type. * May be directly invoked by applications. */ asn_struct_free_f *free_struct; /* Free the structure */ asn_struct_print_f *print_struct; /* Human readable output */ asn_constr_check_f *check_constraints; /* Constraints validator */ ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ der_type_encoder_f *der_encoder; /* Canonical DER encoder */ xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ /*********************************************************************** * Internally useful members. Not to be used by applications directly. * **********************************************************************/ /* * Tags that are expected to occur. */ asn_outmost_tag_f *outmost_tag; /* */ ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ int tags_count; /* Number of tags which are expected */ ber_tlv_tag_t *all_tags;/* Every tag for BER/containment */ int all_tags_count; /* Number of tags */ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ /* * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). */ struct asn_TYPE_member_s *elements; int elements_count; /* * Additional information describing the type, used by appropriate * functions above. */ void *specifics; } asn_TYPE_descriptor_t; /* * This type describes an element of the constructed type, * i.e. SEQUENCE, SET, CHOICE, etc. */ enum asn_TYPE_flags_e { ATF_NOFLAGS, ATF_POINTER = 0x01, /* Represented by the pointer */ ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ }; typedef struct asn_TYPE_member_s { enum asn_TYPE_flags_e flags; /* Element's presentation flags */ int optional; /* Following optional members, including current */ int memb_offset; /* Offset of the element */ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ asn_TYPE_descriptor_t *type; /* Member type descriptor */ asn_constr_check_f *memb_constraints; /* Constraints validator */ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ int (*default_value)(int setval, void **sptr); /* DEFAULT */ char *name; /* ASN.1 identifier of the element */ } asn_TYPE_member_t; /* * BER tag to element number mapping. */ typedef struct asn_TYPE_tag2member_s { ber_tlv_tag_t el_tag; /* Outmost tag of the member */ int el_no; /* Index of the associated member, base 0 */ int toff_first; /* First occurence of the el_tag, relative */ int toff_last; /* Last occurence of the el_tag, relatvie */ } asn_TYPE_tag2member_t; /* * This function is a wrapper around (td)->print_struct, which prints out * the contents of the target language's structure (struct_ptr) into the * file pointer (stream) in human readable form. * RETURN VALUES: * 0: The structure is printed. * -1: Problem dumping the structure. * (See also xer_fprint() in xer_encoder.h) */ int asn_fprint(FILE *stream, /* Destination stream descriptor */ asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ const void *struct_ptr); /* Structure to be printed */ #ifdef __cplusplus } #endif #endif /* _CONSTR_TYPE_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/constraints.c000066400000000000000000000042571266122234600212060ustar00rootroot00000000000000#include "asn_internal.h" #include "constraints.h" int asn_generic_no_constraint(asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { (void)type_descriptor; /* Unused argument */ (void)struct_ptr; /* Unused argument */ (void)cb; /* Unused argument */ (void)key; /* Unused argument */ /* Nothing to check */ return 0; } int asn_generic_unknown_constraint(asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { (void)type_descriptor; /* Unused argument */ (void)struct_ptr; /* Unused argument */ (void)cb; /* Unused argument */ (void)key; /* Unused argument */ /* Unknown how to check */ return 0; } struct errbufDesc { asn_TYPE_descriptor_t *failed_type; const void *failed_struct_ptr; char *errbuf; size_t errlen; }; static void _asn_i_ctfailcb(void *key, asn_TYPE_descriptor_t *td, const void *sptr, const char *fmt, ...) { struct errbufDesc *arg = key; va_list ap; ssize_t vlen; ssize_t maxlen; arg->failed_type = td; arg->failed_struct_ptr = sptr; maxlen = arg->errlen; if(maxlen <= 0) return; va_start(ap, fmt); vlen = vsnprintf(arg->errbuf, maxlen, fmt, ap); va_end(ap); if(vlen >= maxlen) { arg->errbuf[maxlen-1] = '\0'; /* Ensuring libc correctness */ arg->errlen = maxlen - 1; /* Not counting termination */ return; } else if(vlen >= 0) { arg->errbuf[vlen] = '\0'; /* Ensuring libc correctness */ arg->errlen = vlen; /* Not counting termination */ } else { /* * The libc on this system is broken. */ vlen = sizeof("") - 1; maxlen--; arg->errlen = vlen < maxlen ? vlen : maxlen; memcpy(arg->errbuf, "", arg->errlen); arg->errbuf[arg->errlen] = 0; } return; } int asn_check_constraints(asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr, char *errbuf, size_t *errlen) { struct errbufDesc arg; int ret; arg.failed_type = 0; arg.failed_struct_ptr = 0; arg.errbuf = errbuf; arg.errlen = errlen ? *errlen : 0; ret = type_descriptor->check_constraints(type_descriptor, struct_ptr, _asn_i_ctfailcb, &arg); if(ret == -1 && errlen) *errlen = arg.errlen; return ret; } mod_auth_gssapi-1.3.2/src/asn1c/constraints.h000066400000000000000000000036571266122234600212160ustar00rootroot00000000000000/*- * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ #define _ASN1_CONSTRAINTS_VALIDATOR_H_ #include /* Platform-dependent types */ #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * Validate the structure according to the ASN.1 constraints. * If errbuf and errlen are given, they shall be pointing to the appropriate * buffer space and its length before calling this function. Alternatively, * they could be passed as NULL's. If constraints validation fails, * errlen will contain the actual number of bytes taken from the errbuf * to encode an error message (properly 0-terminated). * * RETURN VALUES: * This function returns 0 in case all ASN.1 constraints are met * and -1 if one or more constraints were failed. */ int asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, const void *struct_ptr, /* Target language's structure */ char *errbuf, /* Returned error description */ size_t *errlen /* Length of the error description */ ); /* * Generic type for constraint checking callback, * associated with every type descriptor. */ typedef int (asn_constr_check_f)( struct asn_TYPE_descriptor_s *type_descriptor, const void *struct_ptr, asn_app_constraint_failed_f *optional_callback, /* Log the error */ void *optional_app_key /* Opaque key passed to a callback */ ); /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ /* * Invoke the callback with a complete error message. */ #define _ASN_CTFAIL if(ctfailcb) ctfailcb #ifdef __cplusplus } #endif #endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/der_encoder.c000066400000000000000000000116451266122234600211070ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, asn_app_consume_bytes_f *cb, void *app_key, int constructed); /* * The DER encoder of any type. */ asn_enc_rval_t der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, asn_app_consume_bytes_f *consume_bytes, void *app_key) { ASN_DEBUG("DER encoder invoked for %s", type_descriptor->name); /* * Invoke type-specific encoder. */ return type_descriptor->der_encoder(type_descriptor, struct_ptr, /* Pointer to the destination structure */ 0, 0, consume_bytes, app_key); } /* * Argument type and callback necessary for der_encode_to_buffer(). */ typedef struct enc_to_buf_arg { void *buffer; size_t left; } enc_to_buf_arg; static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { enc_to_buf_arg *arg = (enc_to_buf_arg *)key; if(arg->left < size) return -1; /* Data exceeds the available buffer size */ memcpy(arg->buffer, buffer, size); arg->buffer = ((char *)arg->buffer) + size; arg->left -= size; return 0; } /* * A variant of the der_encode() which encodes the data into the provided buffer */ asn_enc_rval_t der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, void *buffer, size_t buffer_size) { enc_to_buf_arg arg; asn_enc_rval_t ec; arg.buffer = buffer; arg.left = buffer_size; ec = type_descriptor->der_encoder(type_descriptor, struct_ptr, /* Pointer to the destination structure */ 0, 0, encode_to_buffer_cb, &arg); if(ec.encoded != -1) { assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); /* Return the encoded contents size */ } return ec; } /* * Write out leading TL[v] sequence according to the type definition. */ ssize_t der_write_tags(asn_TYPE_descriptor_t *sd, size_t struct_length, int tag_mode, int last_tag_form, ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ asn_app_consume_bytes_f *cb, void *app_key) { ber_tlv_tag_t *tags; /* Copy of tags stream */ int tags_count; /* Number of tags */ size_t overall_length; ssize_t *lens; int i; ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)", sd->name, tag_mode, sd->tags_count, ber_tlv_tag_string(tag), tag_mode ?(sd->tags_count+1 -((tag_mode == -1) && sd->tags_count)) :sd->tags_count ); if(tag_mode) { /* * Instead of doing shaman dance like we do in ber_check_tags(), * allocate a small array on the stack * and initialize it appropriately. */ int stag_offset; tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t)); if(!tags) { /* Can fail on !x86 */ errno = ENOMEM; return -1; } tags_count = sd->tags_count + 1 /* EXPLICIT or IMPLICIT tag is given */ - ((tag_mode == -1) && sd->tags_count); /* Copy tags over */ tags[0] = tag; stag_offset = -1 + ((tag_mode == -1) && sd->tags_count); for(i = 1; i < tags_count; i++) tags[i] = sd->tags[i + stag_offset]; } else { tags = sd->tags; tags_count = sd->tags_count; } /* No tags to write */ if(tags_count == 0) return 0; lens = (ssize_t *)alloca(tags_count * sizeof(lens[0])); if(!lens) { errno = ENOMEM; return -1; } /* * Array of tags is initialized. * Now, compute the size of the TLV pairs, from right to left. */ overall_length = struct_length; for(i = tags_count - 1; i >= 0; --i) { lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0); if(lens[i] == -1) return -1; overall_length += lens[i]; lens[i] = overall_length - lens[i]; } if(!cb) return overall_length - struct_length; ASN_DEBUG("%s %s TL sequence (%d elements)", cb?"Encoding":"Estimating", sd->name, tags_count); /* * Encode the TL sequence for real. */ for(i = 0; i < tags_count; i++) { ssize_t len; int _constr; /* Check if this tag happens to be constructed */ _constr = (last_tag_form || i < (tags_count - 1)); len = der_write_TL(tags[i], lens[i], cb, app_key, _constr); if(len == -1) return -1; } return overall_length - struct_length; } static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, asn_app_consume_bytes_f *cb, void *app_key, int constructed) { uint8_t buf[32]; size_t size = 0; int buf_size = cb?sizeof(buf):0; ssize_t tmp; /* Serialize tag (T from TLV) into possibly zero-length buffer */ tmp = ber_tlv_tag_serialize(tag, buf, buf_size); if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1; size += tmp; /* Serialize length (L from TLV) into possibly zero-length buffer */ tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0); if(tmp == -1) return -1; size += tmp; if(size > sizeof(buf)) return -1; /* * If callback is specified, invoke it, and check its return value. */ if(cb) { if(constructed) *buf |= 0x20; if(cb(buf, size, app_key) < 0) return -1; } return size; } mod_auth_gssapi-1.3.2/src/asn1c/der_encoder.h000066400000000000000000000036311266122234600211100ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _DER_ENCODER_H_ #define _DER_ENCODER_H_ #include #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * The DER encoder of any type. May be invoked by the application. * The ber_decode() function (ber_decoder.h) is an opposite of der_encode(). */ asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ asn_app_consume_bytes_f *consume_bytes_cb, void *app_key /* Arbitrary callback argument */ ); /* A variant of der_encode() which encodes data into the pre-allocated buffer */ asn_enc_rval_t der_encode_to_buffer( struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ void *buffer, /* Pre-allocated buffer */ size_t buffer_size /* Initial buffer size (maximum) */ ); /* * Type of the generic DER encoder. */ typedef asn_enc_rval_t (der_type_encoder_f)( struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ ber_tlv_tag_t tag, asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ void *app_key /* Arbitrary callback argument */ ); /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ /* * Write out leading TL[v] sequence according to the type definition. */ ssize_t der_write_tags( struct asn_TYPE_descriptor_s *type_descriptor, size_t struct_length, int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ int last_tag_form, /* {0,!0}: prim, constructed */ ber_tlv_tag_t tag, asn_app_consume_bytes_f *consume_bytes_cb, void *app_key ); #ifdef __cplusplus } #endif #endif /* _DER_ENCODER_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/per_decoder.c000066400000000000000000000047761266122234600211200ustar00rootroot00000000000000#include #include #include /* * Decode a "Production of a complete encoding", X.691#10.1. * The complete encoding contains at least one byte, and is an integral * multiple of 8 bytes. */ asn_dec_rval_t uper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) { asn_dec_rval_t rval; rval = uper_decode(opt_codec_ctx, td, sptr, buffer, size, 0, 0); if(rval.consumed) { /* * We've always given 8-aligned data, * so convert bits to integral bytes. */ rval.consumed += 7; rval.consumed >>= 3; } else if(rval.code == RC_OK) { if(size) { if(((const uint8_t *)buffer)[0] == 0) { rval.consumed = 1; /* 1 byte */ } else { ASN_DEBUG("Expecting single zeroed byte"); rval.code = RC_FAIL; } } else { /* Must contain at least 8 bits. */ rval.code = RC_WMORE; } } return rval; } asn_dec_rval_t uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { asn_codec_ctx_t s_codec_ctx; asn_dec_rval_t rval; asn_per_data_t pd; if(skip_bits < 0 || skip_bits > 7 || unused_bits < 0 || unused_bits > 7 || (unused_bits > 0 && !size)) _ASN_DECODE_FAILED; /* * Stack checker requires that the codec context * must be allocated on the stack. */ if(opt_codec_ctx) { if(opt_codec_ctx->max_stack_size) { s_codec_ctx = *opt_codec_ctx; opt_codec_ctx = &s_codec_ctx; } } else { /* If context is not given, be security-conscious anyway */ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; opt_codec_ctx = &s_codec_ctx; } /* Fill in the position indicator */ memset(&pd, 0, sizeof(pd)); pd.buffer = (const uint8_t *)buffer; pd.nboff = skip_bits; pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from */ if(pd.nboff > pd.nbits) _ASN_DECODE_FAILED; /* * Invoke type-specific decoder. */ if(!td->uper_decoder) _ASN_DECODE_FAILED; /* PER is not compiled in */ rval = td->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd); if(rval.code == RC_OK) { /* Return the number of consumed bits */ rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) + pd.nboff - skip_bits; ASN_DEBUG("PER decoding consumed %ld, counted %ld", (long)rval.consumed, (long)pd.moved); assert(rval.consumed == pd.moved); } else { /* PER codec is not a restartable */ rval.consumed = 0; } return rval; } mod_auth_gssapi-1.3.2/src/asn1c/per_decoder.h000066400000000000000000000033001266122234600211030ustar00rootroot00000000000000/*- * Copyright (c) 2005, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _PER_DECODER_H_ #define _PER_DECODER_H_ #include #include #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * Unaligned PER decoder of a "complete encoding" as per X.691#10.1. * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3. */ asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ void **struct_ptr, /* Pointer to a target structure's pointer */ const void *buffer, /* Data to be decoded */ size_t size /* Size of data buffer */ ); /* * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. * WARNING: This call returns the number of BITS read from the stream. Beware. */ asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ void **struct_ptr, /* Pointer to a target structure's pointer */ const void *buffer, /* Data to be decoded */ size_t size, /* Size of data buffer */ int skip_bits, /* Number of unused leading bits, 0..7 */ int unused_bits /* Number of unused tailing bits, 0..7 */ ); /* * Type of the type-specific PER decoder function. */ typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, asn_per_constraints_t *constraints, void **struct_ptr, asn_per_data_t *per_data ); #ifdef __cplusplus } #endif #endif /* _PER_DECODER_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/per_encoder.c000066400000000000000000000071651266122234600211250ustar00rootroot00000000000000#include #include #include static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); asn_enc_rval_t uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { return uper_encode_internal(td, 0, sptr, cb, app_key); } /* * Argument type and callback necessary for uper_encode_to_buffer(). */ typedef struct enc_to_buf_arg { void *buffer; size_t left; } enc_to_buf_arg; static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { enc_to_buf_arg *arg = (enc_to_buf_arg *)key; if(arg->left < size) return -1; /* Data exceeds the available buffer size */ memcpy(arg->buffer, buffer, size); arg->buffer = ((char *)arg->buffer) + size; arg->left -= size; return 0; } asn_enc_rval_t uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { enc_to_buf_arg key; key.buffer = buffer; key.left = buffer_size; if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key); } typedef struct enc_dyn_arg { void *buffer; size_t length; size_t allocated; } enc_dyn_arg; static int encode_dyn_cb(const void *buffer, size_t size, void *key) { enc_dyn_arg *arg = key; if(arg->length + size >= arg->allocated) { void *p; arg->allocated = arg->allocated ? (arg->allocated << 2) : size; p = REALLOC(arg->buffer, arg->allocated); if(!p) { FREEMEM(arg->buffer); memset(arg, 0, sizeof(*arg)); return -1; } arg->buffer = p; } memcpy(((char *)arg->buffer) + arg->length, buffer, size); arg->length += size; return 0; } ssize_t uper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) { asn_enc_rval_t er; enc_dyn_arg key; memset(&key, 0, sizeof(key)); er = uper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key); switch(er.encoded) { case -1: FREEMEM(key.buffer); return -1; case 0: FREEMEM(key.buffer); key.buffer = MALLOC(1); if(key.buffer) { *(char *)key.buffer = '\0'; *buffer_r = key.buffer; return 1; } else { return -1; } default: *buffer_r = key.buffer; ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded); return ((er.encoded + 7) >> 3); } } /* * Internally useful functions. */ /* Flush partially filled buffer */ static int _uper_encode_flush_outp(asn_per_outp_t *po) { uint8_t *buf; if(po->nboff == 0 && po->buffer == po->tmpspace) return 0; buf = po->buffer + (po->nboff >> 3); /* Make sure we account for the last, partially filled */ if(po->nboff & 0x07) { buf[0] &= 0xff << (8 - (po->nboff & 0x07)); buf++; } return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); } static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { asn_per_outp_t po; asn_enc_rval_t er; /* * Invoke type-specific encoder. */ if(!td || !td->uper_encoder) _ASN_ENCODE_FAILED; /* PER is not compiled in */ po.buffer = po.tmpspace; po.nboff = 0; po.nbits = 8 * sizeof(po.tmpspace); po.outper = cb; po.op_key = app_key; po.flushed_bytes = 0; er = td->uper_encoder(td, constraints, sptr, &po); if(er.encoded != -1) { size_t bits_to_flush; bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; /* Set number of bits encoded to a firm value */ er.encoded = (po.flushed_bytes << 3) + bits_to_flush; if(_uper_encode_flush_outp(&po)) _ASN_ENCODE_FAILED; } return er; } mod_auth_gssapi-1.3.2/src/asn1c/per_encoder.h000066400000000000000000000041771266122234600211320ustar00rootroot00000000000000/*- * Copyright (c) 2006, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _PER_ENCODER_H_ #define _PER_ENCODER_H_ #include #include #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. * WARNING: This function returns the number of encoded bits in the .encoded * field of the return value. Use the following formula to convert to bytes: * bytes = ((.encoded + 7) / 8) */ asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ void *app_key /* Arbitrary callback argument */ ); /* * A variant of uper_encode() which encodes data into the existing buffer * WARNING: This function returns the number of encoded bits in the .encoded * field of the return value. */ asn_enc_rval_t uper_encode_to_buffer( struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ void *buffer, /* Pre-allocated buffer */ size_t buffer_size /* Initial buffer size (max) */ ); /* * A variant of uper_encode_to_buffer() which allocates buffer itself. * Returns the number of bytes in the buffer or -1 in case of failure. * WARNING: This function produces a "Production of the complete encoding", * with length of at least one octet. Contrast this to precise bit-packing * encoding of uper_encode() and uper_encode_to_buffer(). */ ssize_t uper_encode_to_new_buffer( struct asn_TYPE_descriptor_s *type_descriptor, asn_per_constraints_t *constraints, void *struct_ptr, /* Structure to be encoded */ void **buffer_r /* Buffer allocated and returned */ ); /* * Type of the generic PER encoder function. */ typedef asn_enc_rval_t (per_type_encoder_f)( struct asn_TYPE_descriptor_s *type_descriptor, asn_per_constraints_t *constraints, void *struct_ptr, asn_per_outp_t *per_output ); #ifdef __cplusplus } #endif #endif /* _PER_ENCODER_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/per_opentype.c000066400000000000000000000225361266122234600213500ustar00rootroot00000000000000/* * Copyright (c) 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include #include typedef struct uper_ugot_key { asn_per_data_t oldpd; /* Old per data source */ size_t unclaimed; size_t ot_moved; /* Number of bits moved by OT processing */ int repeat; } uper_ugot_key; static int uper_ugot_refill(asn_per_data_t *pd); static int per_skip_bits(asn_per_data_t *pd, int skip_nbits); static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); /* * Encode an "open type field". * #10.1, #10.2 */ int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { void *buf; void *bptr; ssize_t size; size_t toGo; ASN_DEBUG("Open type put %s ...", td->name); size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); if(size <= 0) return -1; for(bptr = buf, toGo = size; toGo;) { ssize_t maySave = uper_put_length(po, toGo); ASN_DEBUG("Prepending length %d to %s and allowing to save %d", (int)size, td->name, (int)maySave); if(maySave < 0) break; if(per_put_many_bits(po, bptr, maySave * 8)) break; bptr = (char *)bptr + maySave; toGo -= maySave; } FREEMEM(buf); if(toGo) return -1; ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)", td->name, (long)size); return 0; } static asn_dec_rval_t uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { asn_dec_rval_t rv; ssize_t chunk_bytes; int repeat; uint8_t *buf = 0; size_t bufLen = 0; size_t bufSize = 0; asn_per_data_t spd; size_t padding; _ASN_STACK_OVERFLOW_CHECK(ctx); ASN_DEBUG("Getting open type %s...", td->name); do { chunk_bytes = uper_get_length(pd, -1, &repeat); if(chunk_bytes < 0) { FREEMEM(buf); _ASN_DECODE_STARVED; } if(bufLen + chunk_bytes > bufSize) { void *ptr; bufSize = chunk_bytes + (bufSize << 2); ptr = REALLOC(buf, bufSize); if(!ptr) { FREEMEM(buf); _ASN_DECODE_FAILED; } buf = ptr; } if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { FREEMEM(buf); _ASN_DECODE_STARVED; } bufLen += chunk_bytes; } while(repeat); ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name, (long)bufLen); memset(&spd, 0, sizeof(spd)); spd.buffer = buf; spd.nbits = bufLen << 3; ASN_DEBUG_INDENT_ADD(+4); rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); ASN_DEBUG_INDENT_ADD(-4); if(rv.code == RC_OK) { /* Check padding validity */ padding = spd.nbits - spd.nboff; if ((padding < 8 || /* X.691#10.1.3 */ (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) && per_get_few_bits(&spd, padding) == 0) { /* Everything is cool */ FREEMEM(buf); return rv; } FREEMEM(buf); if(padding >= 8) { ASN_DEBUG("Too large padding %d in open type", (int)padding); _ASN_DECODE_FAILED; } else { ASN_DEBUG("Non-zero padding"); _ASN_DECODE_FAILED; } } else { FREEMEM(buf); /* rv.code could be RC_WMORE, nonsense in this context */ rv.code = RC_FAIL; /* Noone would give us more */ } return rv; } static asn_dec_rval_t GCC_NOTUSED uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { uper_ugot_key arg; asn_dec_rval_t rv; ssize_t padding; _ASN_STACK_OVERFLOW_CHECK(ctx); ASN_DEBUG("Getting open type %s from %s", td->name, per_data_string(pd)); arg.oldpd = *pd; arg.unclaimed = 0; arg.ot_moved = 0; arg.repeat = 1; pd->refill = uper_ugot_refill; pd->refill_key = &arg; pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ pd->moved = 0; /* This now counts the open type size in bits */ ASN_DEBUG_INDENT_ADD(+4); rv = td->uper_decoder(ctx, td, constraints, sptr, pd); ASN_DEBUG_INDENT_ADD(-4); #define UPDRESTOREPD do { \ /* buffer and nboff are valid, preserve them. */ \ pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ pd->refill = arg.oldpd.refill; \ pd->refill_key = arg.oldpd.refill_key; \ } while(0) if(rv.code != RC_OK) { UPDRESTOREPD; return rv; } ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name, per_data_string(pd), per_data_string(&arg.oldpd), (int)arg.unclaimed, (int)arg.repeat); padding = pd->moved % 8; if(padding) { int32_t pvalue; if(padding > 7) { ASN_DEBUG("Too large padding %d in open type", (int)padding); rv.code = RC_FAIL; UPDRESTOREPD; return rv; } padding = 8 - padding; ASN_DEBUG("Getting padding of %d bits", (int)padding); pvalue = per_get_few_bits(pd, padding); switch(pvalue) { case -1: ASN_DEBUG("Padding skip failed"); UPDRESTOREPD; _ASN_DECODE_STARVED; case 0: break; default: ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", (int)padding, (int)pvalue); UPDRESTOREPD; _ASN_DECODE_FAILED; } } if(pd->nboff != pd->nbits) { ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, per_data_string(pd), per_data_string(&arg.oldpd)); if(1) { UPDRESTOREPD; _ASN_DECODE_FAILED; } else { arg.unclaimed += pd->nbits - pd->nboff; } } /* Adjust pd back so it points to original data */ UPDRESTOREPD; /* Skip data not consumed by the decoder */ if(arg.unclaimed) { ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed); switch(per_skip_bits(pd, arg.unclaimed)) { case -1: ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed); _ASN_DECODE_STARVED; case 0: ASN_DEBUG("Got claim of %d", (int)arg.unclaimed); break; default: /* Padding must be blank */ ASN_DEBUG("Non-blank unconsumed padding"); _ASN_DECODE_FAILED; } arg.unclaimed = 0; } if(arg.repeat) { ASN_DEBUG("Not consumed the whole thing"); rv.code = RC_FAIL; return rv; } return rv; } asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { return uper_open_type_get_simple(ctx, td, constraints, sptr, pd); } int uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { asn_TYPE_descriptor_t s_td; asn_dec_rval_t rv; s_td.name = ""; s_td.uper_decoder = uper_sot_suck; rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); if(rv.code != RC_OK) return -1; else return 0; } /* * Internal functions. */ static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { asn_dec_rval_t rv; (void)ctx; (void)td; (void)constraints; (void)sptr; while(per_get_few_bits(pd, 24) >= 0); rv.code = RC_OK; rv.consumed = pd->moved; return rv; } static int uper_ugot_refill(asn_per_data_t *pd) { uper_ugot_key *arg = pd->refill_key; ssize_t next_chunk_bytes, next_chunk_bits; ssize_t avail; asn_per_data_t *oldpd = &arg->oldpd; ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld", (long)pd->moved, (long)oldpd->moved); /* Advance our position to where pd is */ oldpd->buffer = pd->buffer; oldpd->nboff = pd->nboff; oldpd->nbits -= pd->moved - arg->ot_moved; oldpd->moved += pd->moved - arg->ot_moved; arg->ot_moved = pd->moved; if(arg->unclaimed) { /* Refill the container */ if(per_get_few_bits(oldpd, 1)) return -1; if(oldpd->nboff == 0) { assert(0); return -1; } pd->buffer = oldpd->buffer; pd->nboff = oldpd->nboff - 1; pd->nbits = oldpd->nbits; ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)", (long)pd->moved); return 0; } if(!arg->repeat) { ASN_DEBUG("Want more but refill doesn't have it"); return -1; } next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld", (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat); if(next_chunk_bytes < 0) return -1; if(next_chunk_bytes == 0) { pd->refill = 0; /* No more refills, naturally */ assert(!arg->repeat); /* Implementation guarantee */ } next_chunk_bits = next_chunk_bytes << 3; avail = oldpd->nbits - oldpd->nboff; if(avail >= next_chunk_bits) { pd->nbits = oldpd->nboff + next_chunk_bits; arg->unclaimed = 0; ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)", (long)next_chunk_bits, (long)oldpd->moved, (long)oldpd->nboff, (long)oldpd->nbits, (long)(oldpd->nbits - oldpd->nboff)); } else { pd->nbits = oldpd->nbits; arg->unclaimed = next_chunk_bits - avail; ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld", (long)avail, (long)next_chunk_bits, (long)arg->unclaimed); } pd->buffer = oldpd->buffer; pd->nboff = oldpd->nboff; ASN_DEBUG("Refilled pd%s old%s", per_data_string(pd), per_data_string(oldpd)); return 0; } static int per_skip_bits(asn_per_data_t *pd, int skip_nbits) { int hasNonZeroBits = 0; while(skip_nbits > 0) { int skip; /* per_get_few_bits() is more efficient when nbits <= 24 */ if(skip_nbits < 24) skip = skip_nbits; else skip = 24; skip_nbits -= skip; switch(per_get_few_bits(pd, skip)) { case -1: return -1; /* Starving */ case 0: continue; /* Skipped empty space */ default: hasNonZeroBits = 1; continue; } } return hasNonZeroBits; } mod_auth_gssapi-1.3.2/src/asn1c/per_opentype.h000066400000000000000000000012321266122234600213430ustar00rootroot00000000000000/* * Copyright (c) 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _PER_OPENTYPE_H_ #define _PER_OPENTYPE_H_ #ifdef __cplusplus extern "C" { #endif asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd); int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); #ifdef __cplusplus } #endif #endif /* _PER_OPENTYPE_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/per_support.c000066400000000000000000000261771266122234600212260ustar00rootroot00000000000000/* * Copyright (c) 2005-2014 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include char * per_data_string(asn_per_data_t *pd) { static char buf[2][32]; static int n; n = (n+1) % 2; snprintf(buf[n], sizeof(buf), "{m=%ld span %+ld[%d..%d] (%d)}", (long)pd->moved, (((long)pd->buffer) & 0xf), (int)pd->nboff, (int)pd->nbits, (int)(pd->nbits - pd->nboff)); return buf[n]; } void per_get_undo(asn_per_data_t *pd, int nbits) { if((ssize_t)pd->nboff < nbits) { assert((ssize_t)pd->nboff < nbits); } else { pd->nboff -= nbits; pd->moved -= nbits; } } /* * Extract a small number of bits (<= 31) from the specified PER data pointer. */ int32_t per_get_few_bits(asn_per_data_t *pd, int nbits) { size_t off; /* Next after last bit offset */ ssize_t nleft; /* Number of bits left in this stream */ uint32_t accum; const uint8_t *buf; if(nbits < 0) return -1; nleft = pd->nbits - pd->nboff; if(nbits > nleft) { int32_t tailv, vhead; if(!pd->refill || nbits > 31) return -1; /* Accumulate unused bytes before refill */ ASN_DEBUG("Obtain the rest %d bits (want %d)", (int)nleft, (int)nbits); tailv = per_get_few_bits(pd, nleft); if(tailv < 0) return -1; /* Refill (replace pd contents with new data) */ if(pd->refill(pd)) return -1; nbits -= nleft; vhead = per_get_few_bits(pd, nbits); /* Combine the rest of previous pd with the head of new one */ tailv = (tailv << nbits) | vhead; /* Could == -1 */ return tailv; } /* * Normalize position indicator. */ if(pd->nboff >= 8) { pd->buffer += (pd->nboff >> 3); pd->nbits -= (pd->nboff & ~0x07); pd->nboff &= 0x07; } pd->moved += nbits; pd->nboff += nbits; off = pd->nboff; buf = pd->buffer; /* * Extract specified number of bits. */ if(off <= 8) accum = nbits ? (buf[0]) >> (8 - off) : 0; else if(off <= 16) accum = ((buf[0] << 8) + buf[1]) >> (16 - off); else if(off <= 24) accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); else if(off <= 31) accum = ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3])) >> (32 - off); else if(nbits <= 31) { asn_per_data_t tpd = *pd; /* Here are we with our 31-bits limit plus 1..7 bits offset. */ per_get_undo(&tpd, nbits); /* The number of available bits in the stream allow * for the following operations to take place without * invoking the ->refill() function */ accum = per_get_few_bits(&tpd, nbits - 24) << 24; accum |= per_get_few_bits(&tpd, 24); } else { per_get_undo(pd, nbits); return -1; } accum &= (((uint32_t)1 << nbits) - 1); ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]", (int)nbits, (int)nleft, (int)pd->moved, (((long)pd->buffer) & 0xf), (int)pd->nboff, (int)pd->nbits, pd->buffer[0], (int)(pd->nbits - pd->nboff), (int)accum); return accum; } /* * Extract a large number of bits from the specified PER data pointer. */ int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { int32_t value; if(alright && (nbits & 7)) { /* Perform right alignment of a first few bits */ value = per_get_few_bits(pd, nbits & 0x07); if(value < 0) return -1; *dst++ = value; /* value is already right-aligned */ nbits &= ~7; } while(nbits) { if(nbits >= 24) { value = per_get_few_bits(pd, 24); if(value < 0) return -1; *(dst++) = value >> 16; *(dst++) = value >> 8; *(dst++) = value; nbits -= 24; } else { value = per_get_few_bits(pd, nbits); if(value < 0) return -1; if(nbits & 7) { /* implies left alignment */ value <<= 8 - (nbits & 7), nbits += 8 - (nbits & 7); if(nbits > 24) *dst++ = value >> 24; } if(nbits > 16) *dst++ = value >> 16; if(nbits > 8) *dst++ = value >> 8; *dst++ = value; break; } } return 0; } /* * Get the length "n" from the stream. */ ssize_t uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { ssize_t value; *repeat = 0; if(ebits >= 0) return per_get_few_bits(pd, ebits); value = per_get_few_bits(pd, 8); if(value < 0) return -1; if((value & 128) == 0) /* #10.9.3.6 */ return (value & 0x7F); if((value & 64) == 0) { /* #10.9.3.7 */ value = ((value & 63) << 8) | per_get_few_bits(pd, 8); if(value < 0) return -1; return value; } value &= 63; /* this is "m" from X.691, #10.9.3.8 */ if(value < 1 || value > 4) return -1; *repeat = 1; return (16384 * value); } /* * Get the normally small length "n". * This procedure used to decode length of extensions bit-maps * for SET and SEQUENCE types. */ ssize_t uper_get_nslength(asn_per_data_t *pd) { ssize_t length; ASN_DEBUG("Getting normally small length"); if(per_get_few_bits(pd, 1) == 0) { length = per_get_few_bits(pd, 6) + 1; if(length <= 0) return -1; ASN_DEBUG("l=%d", (int)length); return length; } else { int repeat; length = uper_get_length(pd, -1, &repeat); if(length >= 0 && !repeat) return length; return -1; /* Error, or do not support >16K extensions */ } } /* * Get the normally small non-negative whole number. * X.691, #10.6 */ ssize_t uper_get_nsnnwn(asn_per_data_t *pd) { ssize_t value; value = per_get_few_bits(pd, 7); if(value & 64) { /* implicit (value < 0) */ value &= 63; value <<= 2; value |= per_get_few_bits(pd, 2); if(value & 128) /* implicit (value < 0) */ return -1; if(value == 0) return 0; if(value >= 3) return -1; value = per_get_few_bits(pd, 8 * value); return value; } return value; } /* * X.691-11/2008, #11.6 * Encoding of a normally small non-negative whole number */ int uper_put_nsnnwn(asn_per_outp_t *po, int n) { int bytes; if(n <= 63) { if(n < 0) return -1; return per_put_few_bits(po, n, 7); } if(n < 256) bytes = 1; else if(n < 65536) bytes = 2; else if(n < 256 * 65536) bytes = 3; else return -1; /* This is not a "normally small" value */ if(per_put_few_bits(po, bytes, 8)) return -1; return per_put_few_bits(po, n, 8 * bytes); } /* X.691-2008/11, #11.5.6 -> #11.3 */ int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) { unsigned long lhalf; /* Lower half of the number*/ long half; if(nbits <= 31) { half = per_get_few_bits(pd, nbits); if(half < 0) return -1; *out_value = half; return 0; } if((size_t)nbits > 8 * sizeof(*out_value)) return -1; /* RANGE */ half = per_get_few_bits(pd, 31); if(half < 0) return -1; if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31)) return -1; *out_value = ((unsigned long)half << (nbits - 31)) | lhalf; return 0; } /* X.691-2008/11, #11.5.6 -> #11.3 */ int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) { /* * Assume signed number can be safely coerced into * unsigned of the same range. * The following testing code will likely be optimized out * by compiler if it is true. */ unsigned long uvalue1 = ULONG_MAX; long svalue = uvalue1; unsigned long uvalue2 = svalue; assert(uvalue1 == uvalue2); return uper_put_constrained_whole_number_u(po, v, nbits); } int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) { if(nbits <= 31) { return per_put_few_bits(po, v, nbits); } else { /* Put higher portion first, followed by lower 31-bit */ if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31)) return -1; return per_put_few_bits(po, v, 31); } } /* * Put a small number of bits (<= 31). */ int per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { size_t off; /* Next after last bit offset */ size_t omsk; /* Existing last byte meaningful bits mask */ uint8_t *buf; if(obits <= 0 || obits >= 32) return obits ? -1 : 0; ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", obits, (int)bits, po->buffer, (int)po->nboff); /* * Normalize position indicator. */ if(po->nboff >= 8) { po->buffer += (po->nboff >> 3); po->nbits -= (po->nboff & ~0x07); po->nboff &= 0x07; } /* * Flush whole-bytes output, if necessary. */ if(po->nboff + obits > po->nbits) { int complete_bytes = (po->buffer - po->tmpspace); ASN_DEBUG("[PER output %ld complete + %ld]", (long)complete_bytes, (long)po->flushed_bytes); if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) return -1; if(po->nboff) po->tmpspace[0] = po->buffer[0]; po->buffer = po->tmpspace; po->nbits = 8 * sizeof(po->tmpspace); po->flushed_bytes += complete_bytes; } /* * Now, due to sizeof(tmpspace), we are guaranteed large enough space. */ buf = po->buffer; omsk = ~((1 << (8 - po->nboff)) - 1); off = (po->nboff + obits); /* Clear data of debris before meaningful bits */ bits &= (((uint32_t)1 << obits) - 1); ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, (int)bits, (int)bits, (int)po->nboff, (int)off, buf[0], (int)(omsk&0xff), (int)(buf[0] & omsk)); if(off <= 8) /* Completely within 1 byte */ po->nboff = off, bits <<= (8 - off), buf[0] = (buf[0] & omsk) | bits; else if(off <= 16) po->nboff = off, bits <<= (16 - off), buf[0] = (buf[0] & omsk) | (bits >> 8), buf[1] = bits; else if(off <= 24) po->nboff = off, bits <<= (24 - off), buf[0] = (buf[0] & omsk) | (bits >> 16), buf[1] = bits >> 8, buf[2] = bits; else if(off <= 31) po->nboff = off, bits <<= (32 - off), buf[0] = (buf[0] & omsk) | (bits >> 24), buf[1] = bits >> 16, buf[2] = bits >> 8, buf[3] = bits; else { per_put_few_bits(po, bits >> (obits - 24), 24); per_put_few_bits(po, bits, obits - 24); } ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]", (int)bits, (int)bits, buf[0], (long)(po->buffer - po->tmpspace)); return 0; } /* * Output a large number of bits. */ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { while(nbits) { uint32_t value; if(nbits >= 24) { value = (src[0] << 16) | (src[1] << 8) | src[2]; src += 3; nbits -= 24; if(per_put_few_bits(po, value, 24)) return -1; } else { value = src[0]; if(nbits > 8) value = (value << 8) | src[1]; if(nbits > 16) value = (value << 8) | src[2]; if(nbits & 0x07) value >>= (8 - (nbits & 0x07)); if(per_put_few_bits(po, value, nbits)) return -1; break; } } return 0; } /* * Put the length "n" (or part of it) into the stream. */ ssize_t uper_put_length(asn_per_outp_t *po, size_t length) { if(length <= 127) /* #10.9.3.6 */ return per_put_few_bits(po, length, 8) ? -1 : (ssize_t)length; else if(length < 16384) /* #10.9.3.7 */ return per_put_few_bits(po, length|0x8000, 16) ? -1 : (ssize_t)length; length >>= 14; if(length > 4) length = 4; return per_put_few_bits(po, 0xC0 | length, 8) ? -1 : (ssize_t)(length << 14); } /* * Put the normally small length "n" into the stream. * This procedure used to encode length of extensions bit-maps * for SET and SEQUENCE types. */ int uper_put_nslength(asn_per_outp_t *po, size_t length) { if(length <= 64) { /* #10.9.3.4 */ if(length == 0) return -1; return per_put_few_bits(po, length-1, 7) ? -1 : 0; } else { if(uper_put_length(po, length) != (ssize_t)length) { /* This might happen in case of >16K extensions */ return -1; } } return 0; } mod_auth_gssapi-1.3.2/src/asn1c/per_support.h000066400000000000000000000102251266122234600212160ustar00rootroot00000000000000/* * Copyright (c) 2005-2014 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _PER_SUPPORT_H_ #define _PER_SUPPORT_H_ #include /* Platform-specific types */ #ifdef __cplusplus extern "C" { #endif /* * Pre-computed PER constraints. */ typedef struct asn_per_constraint_s { enum asn_per_constraint_flags { APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ APC_CONSTRAINED = 0x2, /* Fully constrained */ APC_EXTENSIBLE = 0x4 /* May have extension */ } flags; int range_bits; /* Full number of bits in the range */ int effective_bits; /* Effective bits */ long lower_bound; /* "lb" value */ long upper_bound; /* "ub" value */ } asn_per_constraint_t; typedef struct asn_per_constraints_s { asn_per_constraint_t value; asn_per_constraint_t size; int (*value2code)(unsigned int value); int (*code2value)(unsigned int code); } asn_per_constraints_t; /* * This structure describes a position inside an incoming PER bit stream. */ typedef struct asn_per_data_s { const uint8_t *buffer; /* Pointer to the octet stream */ size_t nboff; /* Bit offset to the meaningful bit */ size_t nbits; /* Number of bits in the stream */ size_t moved; /* Number of bits moved through this bit stream */ int (*refill)(struct asn_per_data_s *); void *refill_key; } asn_per_data_t; /* * Extract a small number of bits (<= 31) from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be * extracted due to EOD or other conditions. */ int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); /* Undo the immediately preceeding "get_few_bits" operation */ void per_get_undo(asn_per_data_t *per_data, int get_nbits); /* * Extract a large number of bits from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be * extracted due to EOD or other conditions. */ int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, int get_nbits); /* * Get the length "n" from the Unaligned PER stream. */ ssize_t uper_get_length(asn_per_data_t *pd, int effective_bound_bits, int *repeat); /* * Get the normally small length "n". */ ssize_t uper_get_nslength(asn_per_data_t *pd); /* * Get the normally small non-negative whole number. */ ssize_t uper_get_nsnnwn(asn_per_data_t *pd); /* X.691-2008/11, #11.5.6 */ int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits); /* Non-thread-safe debugging function, don't use it */ char *per_data_string(asn_per_data_t *pd); /* * This structure supports forming PER output. */ typedef struct asn_per_outp_s { uint8_t *buffer; /* Pointer into the (tmpspace) */ size_t nboff; /* Bit offset to the meaningful bit */ size_t nbits; /* Number of bits left in (tmpspace) */ uint8_t tmpspace[32]; /* Preliminary storage to hold data */ int (*outper)(const void *data, size_t size, void *op_key); void *op_key; /* Key for (outper) data callback */ size_t flushed_bytes; /* Bytes already flushed through (outper) */ } asn_per_outp_t; /* Output a small number of bits (<= 31) */ int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); /* Output a large number of bits */ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); /* X.691-2008/11, #11.5 */ int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits); int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits); /* * Put the length "n" to the Unaligned PER stream. * This function returns the number of units which may be flushed * in the next units saving iteration. */ ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); /* * Put the normally small length "n" to the Unaligned PER stream. * Returns 0 or -1. */ int uper_put_nslength(asn_per_outp_t *po, size_t length); /* * Put the normally small non-negative whole number. */ int uper_put_nsnnwn(asn_per_outp_t *po, int n); #ifdef __cplusplus } #endif #endif /* _PER_SUPPORT_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/session.asn1000066400000000000000000000005221266122234600207310ustar00rootroot00000000000000GssapiSessionModule DEFINITIONS ::= BEGIN Uint32 ::= INTEGER (0..4294967295) GSSSessionData ::= SEQUENCE { established [0] BOOLEAN, delegated [1] BOOLEAN, expiration [2] Uint32, username [3] OCTET STRING, gssname [4] OCTET STRING, basichash [5] OCTET STRING } END mod_auth_gssapi-1.3.2/src/asn1c/xer_decoder.c000066400000000000000000000210371266122234600211150ustar00rootroot00000000000000/* * Copyright (c) 2004, 2005 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* XER/XML parsing support */ /* * Decode the XER encoding of a given type. */ asn_dec_rval_t xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **struct_ptr, const void *buffer, size_t size) { asn_codec_ctx_t s_codec_ctx; /* * Stack checker requires that the codec context * must be allocated on the stack. */ if(opt_codec_ctx) { if(opt_codec_ctx->max_stack_size) { s_codec_ctx = *opt_codec_ctx; opt_codec_ctx = &s_codec_ctx; } } else { /* If context is not given, be security-conscious anyway */ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; opt_codec_ctx = &s_codec_ctx; } /* * Invoke type-specific decoder. */ return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size); } struct xer__cb_arg { pxml_chunk_type_e chunk_type; size_t chunk_size; const void *chunk_buf; int callback_not_invoked; }; static int xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) { struct xer__cb_arg *arg = (struct xer__cb_arg *)key; arg->chunk_type = type; arg->chunk_size = _chunk_size; arg->chunk_buf = _chunk_data; arg->callback_not_invoked = 0; return -1; /* Terminate the XML parsing */ } /* * Fetch the next token from the XER/XML stream. */ ssize_t xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) { struct xer__cb_arg arg; int new_stateContext = *stateContext; ssize_t ret; arg.callback_not_invoked = 1; ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg); if(ret < 0) return -1; if(arg.callback_not_invoked) { assert(ret == 0); /* No data was consumed */ return 0; /* Try again with more data */ } else { assert(arg.chunk_size); assert(arg.chunk_buf == buffer); } /* * Translate the XML chunk types into more convenient ones. */ switch(arg.chunk_type) { case PXML_TEXT: *ch_type = PXER_TEXT; break; case PXML_TAG: return 0; /* Want more */ case PXML_TAG_END: *ch_type = PXER_TAG; break; case PXML_COMMENT: case PXML_COMMENT_END: *ch_type = PXER_COMMENT; break; } *stateContext = new_stateContext; return arg.chunk_size; } #define CSLASH 0x2f /* '/' */ #define LANGLE 0x3c /* '<' */ #define RANGLE 0x3e /* '>' */ xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { const char *buf = (const char *)buf_ptr; const char *end; xer_check_tag_e ct = XCT_OPENING; if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) { if(size >= 2) ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]); return XCT_BROKEN; } /* * Determine the tag class. */ if(buf[1] == CSLASH) { buf += 2; /* advance past "" */ ct = XCT_CLOSING; if(size > 0 && buf[size-1] == CSLASH) return XCT_BROKEN; /* */ } else { buf++; /* advance past "<" */ size -= 2; /* strip "<" and ">" */ if(size > 0 && buf[size-1] == CSLASH) { ct = XCT_BOTH; size--; /* One more, for "/" */ } } /* Sometimes we don't care about the tag */ if(!need_tag || !*need_tag) return (xer_check_tag_e)(XCT__UNK__MASK | ct); /* * Determine the tag name. */ for(end = buf + size; buf < end; buf++, need_tag++) { int b = *buf, n = *need_tag; if(b != n) { if(n == 0) { switch(b) { case 0x09: case 0x0a: case 0x0c: case 0x0d: case 0x20: /* "": whitespace is normal */ return ct; } } return (xer_check_tag_e)(XCT__UNK__MASK | ct); } if(b == 0) return XCT_BROKEN; /* Embedded 0 in buf?! */ } if(*need_tag) return (xer_check_tag_e)(XCT__UNK__MASK | ct); return ct; } #undef ADVANCE #define ADVANCE(num_bytes) do { \ size_t num = (num_bytes); \ buf_ptr = ((const char *)buf_ptr) + num; \ size -= num; \ consumed_myself += num; \ } while(0) #undef RETURN #define RETURN(_code) do { \ rval.code = _code; \ rval.consumed = consumed_myself; \ if(rval.code != RC_OK) \ ASN_DEBUG("Failed with %d", rval.code); \ return rval; \ } while(0) #define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ ssize_t converted_size = body_receiver \ (struct_key, chunk_buf, chunk_size, \ (size_t)chunk_size < size); \ if(converted_size == -1) RETURN(RC_FAIL); \ if(converted_size == 0 \ && size == (size_t)chunk_size) \ RETURN(RC_WMORE); \ chunk_size = converted_size; \ } while(0) #define XER_GOT_EMPTY() do { \ if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ RETURN(RC_FAIL); \ } while(0) /* * Generalized function for decoding the primitive values. */ asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, asn_struct_ctx_t *ctx, /* Type decoder context */ void *struct_key, const char *xml_tag, /* Expected XML tag */ const void *buf_ptr, size_t size, int (*opt_unexpected_tag_decoder) (void *struct_key, const void *chunk_buf, size_t chunk_size), ssize_t (*body_receiver) (void *struct_key, const void *chunk_buf, size_t chunk_size, int have_more) ) { asn_dec_rval_t rval; ssize_t consumed_myself = 0; (void)opt_codec_ctx; /* * Phases of XER/XML processing: * Phase 0: Check that the opening tag matches our expectations. * Phase 1: Processing body and reacting on closing tag. */ if(ctx->phase > 1) RETURN(RC_FAIL); for(;;) { pxer_chunk_type_e ch_type; /* XER chunk type */ ssize_t ch_size; /* Chunk size */ xer_check_tag_e tcv; /* Tag check value */ /* * Get the next part of the XML stream. */ ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type); switch(ch_size) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); default: switch(ch_type) { case PXER_COMMENT: /* Got XML comment */ ADVANCE(ch_size); /* Skip silently */ continue; case PXER_TEXT: if(ctx->phase == 0) { /* * We have to ignore whitespace here, * but in order to be forward compatible * with EXTENDED-XER (EMBED-VALUES, #25) * any text is just ignored here. */ } else { XER_GOT_BODY(buf_ptr, ch_size, size); } ADVANCE(ch_size); continue; case PXER_TAG: break; /* Check the rest down there */ } } assert(ch_type == PXER_TAG && size); tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); /* * Phase 0: * Expecting the opening tag * for the type being processed. * Phase 1: * Waiting for the closing XML tag. */ switch(tcv) { case XCT_BOTH: if(ctx->phase) break; /* Finished decoding of an empty element */ XER_GOT_EMPTY(); ADVANCE(ch_size); ctx->phase = 2; /* Phase out */ RETURN(RC_OK); case XCT_OPENING: if(ctx->phase) break; ADVANCE(ch_size); ctx->phase = 1; /* Processing body phase */ continue; case XCT_CLOSING: if(!ctx->phase) break; ADVANCE(ch_size); ctx->phase = 2; /* Phase out */ RETURN(RC_OK); case XCT_UNKNOWN_BO: /* * Certain tags in the body may be expected. */ if(opt_unexpected_tag_decoder && opt_unexpected_tag_decoder(struct_key, buf_ptr, ch_size) >= 0) { /* Tag's processed fine */ ADVANCE(ch_size); if(!ctx->phase) { /* We are not expecting * the closing tag anymore. */ ctx->phase = 2; /* Phase out */ RETURN(RC_OK); } continue; } /* Fall through */ default: break; /* Unexpected tag */ } ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag); break; /* Dark and mysterious things have just happened */ } RETURN(RC_FAIL); } size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size) { const char *p = (const char *)chunk_buf; const char *pend = p + chunk_size; for(; p < pend; p++) { switch(*p) { /* X.693, #8.1.4 * HORISONTAL TAB (9) * LINE FEED (10) * CARRIAGE RETURN (13) * SPACE (32) */ case 0x09: case 0x0a: case 0x0d: case 0x20: continue; default: break; } break; } return (p - (const char *)chunk_buf); } /* * This is a vastly simplified, non-validating XML tree skipper. */ int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) { assert(*depth > 0); switch(tcv) { case XCT_BOTH: case XCT_UNKNOWN_BO: /* These negate each other. */ return 0; case XCT_OPENING: case XCT_UNKNOWN_OP: ++(*depth); return 0; case XCT_CLOSING: case XCT_UNKNOWN_CL: if(--(*depth) == 0) return (tcv == XCT_CLOSING) ? 2 : 1; return 0; default: return -1; } } mod_auth_gssapi-1.3.2/src/asn1c/xer_decoder.h000066400000000000000000000064161266122234600211260ustar00rootroot00000000000000/*- * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _XER_DECODER_H_ #define _XER_DECODER_H_ #include #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * The XER decoder of any ASN.1 type. May be invoked by the application. */ asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, void **struct_ptr, /* Pointer to a target structure's pointer */ const void *buffer, /* Data to be decoded */ size_t size /* Size of data buffer */ ); /* * Type of the type-specific XER decoder function. */ typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, void **struct_ptr, const char *opt_mname, /* Member name */ const void *buf_ptr, size_t size ); /******************************* * INTERNALLY USEFUL FUNCTIONS * *******************************/ /* * Generalized function for decoding the primitive values. * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 * and others. This function should not be used by applications, as its API * is subject to changes. */ asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, asn_struct_ctx_t *ctx, /* Type decoder context */ void *struct_key, /* Treated as opaque pointer */ const char *xml_tag, /* Expected XML tag name */ const void *buf_ptr, size_t size, int (*opt_unexpected_tag_decoder) (void *struct_key, const void *chunk_buf, size_t chunk_size), ssize_t (*body_receiver) (void *struct_key, const void *chunk_buf, size_t chunk_size, int have_more) ); /* * Fetch the next XER (XML) token from the stream. * The function returns the number of bytes occupied by the chunk type, * returned in the _ch_type. The _ch_type is only set (and valid) when * the return value is greater than 0. */ typedef enum pxer_chunk_type { PXER_TAG, /* Complete XER tag */ PXER_TEXT, /* Plain text between XER tags */ PXER_COMMENT /* A comment, may be part of */ } pxer_chunk_type_e; ssize_t xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); /* * This function checks the buffer against the tag name is expected to occur. */ typedef enum xer_check_tag { XCT_BROKEN = 0, /* The tag is broken */ XCT_OPENING = 1, /* This is the tag */ XCT_CLOSING = 2, /* This is the tag */ XCT_BOTH = 3, /* This is the tag */ XCT__UNK__MASK = 4, /* Mask of everything unexpected */ XCT_UNKNOWN_OP = 5, /* Unexpected tag */ XCT_UNKNOWN_CL = 6, /* Unexpected tag */ XCT_UNKNOWN_BO = 7 /* Unexpected tag */ } xer_check_tag_e; xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, const char *need_tag); /* * Get the number of bytes consisting entirely of XER whitespace characters. * RETURN VALUES: * >=0: Number of whitespace characters in the string. */ size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size); /* * Skip the series of anticipated extensions. */ int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); #ifdef __cplusplus } #endif #endif /* _XER_DECODER_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/xer_encoder.c000066400000000000000000000030051266122234600211220ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include /* * The XER encoder of any type. May be invoked by the application. */ asn_enc_rval_t xer_encode(asn_TYPE_descriptor_t *td, void *sptr, enum xer_encoder_flags_e xer_flags, asn_app_consume_bytes_f *cb, void *app_key) { asn_enc_rval_t er, tmper; const char *mname; size_t mlen; int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2; if(!td || !sptr) goto cb_failed; mname = td->xml_tag; mlen = strlen(mname); _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); tmper = td->xer_encoder(td, sptr, 1, xer_flags, cb, app_key); if(tmper.encoded == -1) return tmper; _ASN_CALLBACK3("\n", xcan); er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; _ASN_ENCODED_OK(er); cb_failed: _ASN_ENCODE_FAILED; } /* * This is a helper function for xer_fprint, which directs all incoming data * into the provided file descriptor. */ static int xer__print2fp(const void *buffer, size_t size, void *app_key) { FILE *stream = (FILE *)app_key; if(fwrite(buffer, 1, size, stream) != size) return -1; return 0; } int xer_fprint(FILE *stream, asn_TYPE_descriptor_t *td, void *sptr) { asn_enc_rval_t er; if(!stream) stream = stdout; if(!td || !sptr) return -1; er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream); if(er.encoded == -1) return -1; return fflush(stream); } mod_auth_gssapi-1.3.2/src/asn1c/xer_encoder.h000066400000000000000000000032411266122234600211310ustar00rootroot00000000000000/*- * Copyright (c) 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _XER_ENCODER_H_ #define _XER_ENCODER_H_ #include #ifdef __cplusplus extern "C" { #endif struct asn_TYPE_descriptor_s; /* Forward declaration */ /* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ enum xer_encoder_flags_e { /* Mode of encoding */ XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ }; /* * The XER encoder of any type. May be invoked by the application. */ asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ enum xer_encoder_flags_e xer_flags, asn_app_consume_bytes_f *consume_bytes_cb, void *app_key /* Arbitrary callback argument */ ); /* * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) * output into the chosen file pointer. * RETURN VALUES: * 0: The structure is printed. * -1: Problem printing the structure. * WARNING: No sensible errno value is returned. */ int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); /* * Type of the generic XER encoder. */ typedef asn_enc_rval_t (xer_type_encoder_f)( struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ int ilevel, /* Level of indentation */ enum xer_encoder_flags_e xer_flags, asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ void *app_key /* Arbitrary callback argument */ ); #ifdef __cplusplus } #endif #endif /* _XER_ENCODER_H_ */ mod_auth_gssapi-1.3.2/src/asn1c/xer_support.c000066400000000000000000000126551266122234600212320ustar00rootroot00000000000000/* * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. * Copyright (c) 2003, 2004, 2005 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include /* Parser states */ typedef enum { ST_TEXT, ST_TAG_START, ST_TAG_BODY, ST_TAG_QUOTE_WAIT, ST_TAG_QUOTED_STRING, ST_TAG_UNQUOTED_STRING, ST_COMMENT_WAIT_DASH1, /* ""[0] */ ST_COMMENT_CLO_RT /* "-->"[1] */ } pstate_e; static pxml_chunk_type_e final_chunk_type[] = { PXML_TEXT, PXML_TAG_END, PXML_COMMENT_END, PXML_TAG_END, PXML_COMMENT_END, }; static int _charclass[256] = { 0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0, /* 01234567 89 */ 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* ABCDEFG HIJKLMNO */ 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0, /* PQRSTUVW XYZ */ 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* abcdefg hijklmno */ 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0 /* pqrstuvw xyz */ }; #define WHITESPACE(c) (_charclass[(unsigned char)(c)] == 1) #define ALNUM(c) (_charclass[(unsigned char)(c)] >= 2) #define ALPHA(c) (_charclass[(unsigned char)(c)] == 3) /* Aliases for characters, ASCII/UTF-8 */ #define EXCLAM 0x21 /* '!' */ #define CQUOTE 0x22 /* '"' */ #define CDASH 0x2d /* '-' */ #define CSLASH 0x2f /* '/' */ #define LANGLE 0x3c /* '<' */ #define CEQUAL 0x3d /* '=' */ #define RANGLE 0x3e /* '>' */ #define CQUEST 0x3f /* '?' */ /* Invoke token callback */ #define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ int _ret; \ pstate_e ns = _ns; \ ssize_t _sz = (p - chunk_start) + _current_too; \ if (!_sz) { \ /* Shortcut */ \ state = _ns; \ break; \ } \ _ret = cb(type, chunk_start, _sz, key); \ if(_ret < _sz) { \ if(_current_too && _ret == -1) \ state = ns; \ goto finish; \ } \ chunk_start = p + _current_too; \ state = ns; \ } while(0) #define TOKEN_CB(_type, _ns, _current_too) \ TOKEN_CB_CALL(_type, _ns, _current_too, 0) #define TOKEN_CB_FINAL(_type, _ns, _current_too) \ TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1) /* * Parser itself */ ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) { pstate_e state = (pstate_e)*stateContext; const char *chunk_start = (const char *)xmlbuf; const char *p = chunk_start; const char *end = p + size; for(; p < end; p++) { int C = *(const unsigned char *)p; switch(state) { case ST_TEXT: /* * Initial state: we're in the middle of some text, * or just have started. */ if (C == LANGLE) /* We're now in the tag, probably */ TOKEN_CB(PXML_TEXT, ST_TAG_START, 0); break; case ST_TAG_START: if (ALPHA(C) || (C == CSLASH)) state = ST_TAG_BODY; else if (C == EXCLAM) state = ST_COMMENT_WAIT_DASH1; else /* * Not characters and not whitespace. * Must be something like "3 < 4". */ TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */ break; case ST_TAG_BODY: switch(C) { case RANGLE: /* End of the tag */ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); break; case LANGLE: /* * The previous tag wasn't completed, but still * recognized as valid. (Mozilla-compatible) */ TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0); break; case CEQUAL: state = ST_TAG_QUOTE_WAIT; break; } break; case ST_TAG_QUOTE_WAIT: /* * State after the equal sign ("=") in the tag. */ switch(C) { case CQUOTE: state = ST_TAG_QUOTED_STRING; break; case RANGLE: /* End of the tag */ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); break; default: if(!WHITESPACE(C)) /* Unquoted string value */ state = ST_TAG_UNQUOTED_STRING; } break; case ST_TAG_QUOTED_STRING: /* * Tag attribute's string value in quotes. */ if(C == CQUOTE) { /* Return back to the tag state */ state = ST_TAG_BODY; } break; case ST_TAG_UNQUOTED_STRING: if(C == RANGLE) { /* End of the tag */ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); } else if(WHITESPACE(C)) { /* Return back to the tag state */ state = ST_TAG_BODY; } break; case ST_COMMENT_WAIT_DASH1: if(C == CDASH) { state = ST_COMMENT_WAIT_DASH2; } else { /* Some ordinary tag. */ state = ST_TAG_BODY; } break; case ST_COMMENT_WAIT_DASH2: if(C == CDASH) { /* Seen "<--" */ state = ST_COMMENT; } else { /* Some ordinary tag */ state = ST_TAG_BODY; } break; case ST_COMMENT: if(C == CDASH) { state = ST_COMMENT_CLO_DASH2; } break; case ST_COMMENT_CLO_DASH2: if(C == CDASH) { state = ST_COMMENT_CLO_RT; } else { /* This is not an end of a comment */ state = ST_COMMENT; } break; case ST_COMMENT_CLO_RT: if(C == RANGLE) { TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1); } else if(C == CDASH) { /* Maintain current state, still waiting for '>' */ } else { state = ST_COMMENT; } break; } /* switch(*ptr) */ } /* for() */ /* * Flush the partially processed chunk, state permitting. */ if(p - chunk_start) { switch (state) { case ST_COMMENT: TOKEN_CB(PXML_COMMENT, state, 0); break; case ST_TEXT: TOKEN_CB(PXML_TEXT, state, 0); break; default: break; /* a no-op */ } } finish: *stateContext = (int)state; return chunk_start - (const char *)xmlbuf; } mod_auth_gssapi-1.3.2/src/asn1c/xer_support.h000066400000000000000000000034241266122234600212310ustar00rootroot00000000000000/* * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _XER_SUPPORT_H_ #define _XER_SUPPORT_H_ #include /* Platform-specific types */ #ifdef __cplusplus extern "C" { #endif /* * Types of data transferred to the application. */ typedef enum { PXML_TEXT, /* Plain text between XML tags. */ PXML_TAG, /* A tag, starting with '<'. */ PXML_COMMENT, /* An XML comment, including "". */ /* * The following chunk types are reported if the chunk * terminates the specified XML element. */ PXML_TAG_END, /* Tag ended */ PXML_COMMENT_END /* Comment ended */ } pxml_chunk_type_e; /* * Callback function that is called by the parser when parsed data is * available. The _opaque is the pointer to a field containing opaque user * data specified in pxml_create() call. The chunk type is _type and the text * data is the piece of buffer identified by _bufid (as supplied to * pxml_feed() call) starting at offset _offset and of _size bytes size. * The chunk is NOT '\0'-terminated. */ typedef int (pxml_callback_f)(pxml_chunk_type_e _type, const void *_chunk_data, size_t _chunk_size, void *_key); /* * Parse the given buffer as it were a chunk of XML data. * Invoke the specified callback each time the meaninful data is found. * This function returns number of bytes consumed from the bufer. * It will always be lesser than or equal to the specified _size. * The next invocation of this function must account the difference. */ ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, pxml_callback_f *cb, void *_key); #ifdef __cplusplus } #endif #endif /* _XER_SUPPORT_H_ */ mod_auth_gssapi-1.3.2/src/crypto.c000066400000000000000000000135371266122234600171530ustar00rootroot00000000000000/* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */ #include #include #include #include #include "crypto.h" struct seal_key { const EVP_CIPHER *cipher; const EVP_MD *md; unsigned char *ekey; unsigned char *hkey; }; apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey, struct databuf *keys) { struct seal_key *n; int keylen; int ret; n = apr_pcalloc(p, sizeof(*n)); if (!n) return ENOMEM; n->cipher = EVP_aes_128_cbc(); if (!n->cipher) { ret = EFAULT; goto done; } keylen = n->cipher->key_len; n->md = EVP_sha256(); if (!n->md) { ret = EFAULT; goto done; } n->ekey = apr_palloc(p, keylen); if (!n->ekey) { ret = ENOMEM; goto done; } n->hkey = apr_palloc(p, keylen); if (!n->hkey) { ret = ENOMEM; goto done; } if (keys) { if (keys->length != (keylen * 2)) { ret = EINVAL; goto done; } memcpy(n->ekey, keys->value, keylen); memcpy(n->hkey, keys->value + keylen, keylen); } else { ret = apr_generate_random_bytes(n->ekey, keylen); if (ret != 0) { ret = EFAULT; goto done; } ret = apr_generate_random_bytes(n->hkey, keylen); if (ret != 0) { ret = EFAULT; goto done; } } ret = 0; done: if (ret == 0) { *skey = n; } return ret; } apr_status_t HMAC_BUFFER(struct seal_key *skey, struct databuf *buffer, struct databuf *result) { HMAC_CTX hmac_ctx = { 0 }; unsigned int len; int ret; /* now MAC the buffer */ HMAC_CTX_init(&hmac_ctx); ret = HMAC_Init_ex(&hmac_ctx, skey->hkey, skey->cipher->key_len, skey->md, NULL); if (ret == 0) goto done; ret = HMAC_Update(&hmac_ctx, buffer->value, buffer->length); if (ret == 0) goto done; ret = HMAC_Final(&hmac_ctx, result->value, &len); done: HMAC_CTX_cleanup(&hmac_ctx); if (ret == 0) return EFAULT; result->length = len; return 0; } apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey, struct databuf *plain, struct databuf *cipher) { int blksz = skey->cipher->block_size; apr_status_t err = EFAULT; EVP_CIPHER_CTX ctx = { 0 }; uint8_t rbuf[blksz]; struct databuf hmacbuf; int outlen, totlen; int ret; EVP_CIPHER_CTX_init(&ctx); /* confounder to avoid exposing random numbers directly to clients * as IVs */ ret = apr_generate_random_bytes(rbuf, sizeof(rbuf)); if (ret != 0) goto done; if (cipher->length == 0) { /* add space for confounder and padding and MAC */ cipher->length = (plain->length / blksz + 2) * blksz; cipher->value = apr_palloc(p, cipher->length + skey->md->md_size); if (!cipher->value) { err = ENOMEM; goto done; } } ret = EVP_EncryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL); if (ret == 0) goto done; totlen = 0; outlen = cipher->length; ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, sizeof(rbuf)); if (ret == 0) goto done; totlen += outlen; outlen = cipher->length - totlen; ret = EVP_EncryptUpdate(&ctx, &cipher->value[totlen], &outlen, plain->value, plain->length); if (ret == 0) goto done; totlen += outlen; outlen = cipher->length - totlen; ret = EVP_EncryptFinal_ex(&ctx, &cipher->value[totlen], &outlen); if (ret == 0) goto done; totlen += outlen; /* now MAC the buffer */ cipher->length = totlen; hmacbuf.value = &cipher->value[totlen]; ret = HMAC_BUFFER(skey, cipher, &hmacbuf); if (ret != 0) goto done; cipher->length += hmacbuf.length; err = 0; done: EVP_CIPHER_CTX_cleanup(&ctx); return err; } apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey, struct databuf *cipher, struct databuf *plain) { apr_status_t err = EFAULT; EVP_CIPHER_CTX ctx = { 0 }; unsigned char mac[skey->md->md_size]; struct databuf hmacbuf; int outlen, totlen; volatile bool equal = true; int ret, i; /* check MAC first */ cipher->length -= skey->md->md_size; hmacbuf.value = mac; ret = HMAC_BUFFER(skey, cipher, &hmacbuf); if (ret != 0) goto done; if (hmacbuf.length != skey->md->md_size) goto done; for (i = 0; i < skey->md->md_size; i++) { if (cipher->value[cipher->length + i] != mac[i]) equal = false; /* not breaking intentionally, * or we would allow an oracle attack */ } if (!equal) goto done; EVP_CIPHER_CTX_init(&ctx); if (plain->length == 0) { plain->length = cipher->length; plain->value = apr_palloc(p, plain->length); if (!plain->value) { err = ENOMEM; goto done; } } ret = EVP_DecryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL); if (ret == 0) goto done; totlen = 0; outlen = plain->length; ret = EVP_DecryptUpdate(&ctx, plain->value, &outlen, cipher->value, cipher->length); if (ret == 0) goto done; totlen += outlen; outlen = plain->length - totlen; ret = EVP_DecryptFinal_ex(&ctx, plain->value, &outlen); if (ret == 0) goto done; totlen += outlen; /* now remove the confounder */ totlen -= skey->cipher->block_size; memmove(plain->value, plain->value + skey->cipher->block_size, totlen); plain->length = totlen; err = 0; done: EVP_CIPHER_CTX_cleanup(&ctx); return err; } int get_mac_size(struct seal_key *skey) { if (skey) { return skey->md->md_size; } else { return 0; } } mod_auth_gssapi-1.3.2/src/crypto.h000066400000000000000000000013751266122234600171550ustar00rootroot00000000000000/* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */ #include #include struct seal_key; struct databuf { unsigned char *value; int length; }; apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey, struct databuf *keys); apr_status_t HMAC_BUFFER(struct seal_key *skey, struct databuf *buffer, struct databuf *result); apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey, struct databuf *plain, struct databuf *cipher); apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey, struct databuf *cipher, struct databuf *plain); int get_mac_size(struct seal_key *skey); mod_auth_gssapi-1.3.2/src/environ.c000066400000000000000000000227441266122234600173130ustar00rootroot00000000000000/* Copyright (C) 2015 mod_auth_gssapi authors - See COPYING for (C) terms */ #include "mod_auth_gssapi.h" struct name_attr { gss_buffer_desc name; int authenticated; int complete; gss_buffer_desc value; gss_buffer_desc display_value; const char *env_name; int number; int more; }; static bool mag_get_name_attr(request_rec *req, gss_name_t name, struct name_attr *attr) { uint32_t maj, min; maj = gss_get_name_attribute(&min, name, &attr->name, &attr->authenticated, &attr->complete, &attr->value, &attr->display_value, &attr->more); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "gss_get_name_attribute() failed on %.*s%s", (int)attr->name.length, (char *)attr->name.value, mag_error(req, "", maj, min)); return false; } return true; } static void mc_add_name_attribute(struct mag_conn *mc, const char *name, const char *value) { size_t size; if (mc->na_count % 16 == 0) { size = sizeof(struct mag_attr) * (mc->na_count + 16); mc->name_attributes = realloc(mc->name_attributes, size); if (!mc->name_attributes) apr_pool_abort_get(mc->pool)(ENOMEM); } mc->name_attributes[mc->na_count].name = apr_pstrdup(mc->pool, name); mc->name_attributes[mc->na_count].value = apr_pstrdup(mc->pool, value); mc->na_count++; } static void mag_set_env_name_attr(request_rec *req, struct mag_conn *mc, struct name_attr *attr) { char *value = ""; int len = 0; /* Prefer a display_value, otherwise fallback to value */ if (attr->display_value.length != 0) { len = attr->display_value.length; value = (char *)attr->display_value.value; } else if (attr->value.length != 0) { len = apr_base64_encode_len(attr->value.length); value = apr_pcalloc(req->pool, len); len = apr_base64_encode(value, (char *)attr->value.value, attr->value.length); } if (attr->number == 1) { mc_add_name_attribute(mc, attr->env_name, apr_psprintf(req->pool, "%.*s", len, value)); } if (attr->more != 0 || attr->number > 1) { mc_add_name_attribute(mc, apr_psprintf(req->pool, "%s_%d", attr->env_name, attr->number), apr_psprintf(req->pool, "%.*s", len, value)); } if (attr->more == 0 && attr->number > 1) { mc_add_name_attribute(mc, apr_psprintf(req->pool, "%s_N", attr->env_name), apr_psprintf(req->pool, "%d", attr->number - 1)); } } static void mag_add_json_name_attr(request_rec *req, bool first, struct name_attr *attr, char **json) { const char *value = ""; int len = 0; char *b64value = NULL; int b64len = 0; const char *vstart = ""; const char *vend = ""; const char *vformat; if (attr->value.length != 0) { b64len = apr_base64_encode_len(attr->value.length); b64value = apr_pcalloc(req->pool, b64len); b64len = apr_base64_encode(b64value, (char *)attr->value.value, attr->value.length); } if (attr->display_value.length != 0) { len = attr->display_value.length; value = (const char *)attr->display_value.value; } if (attr->number == 1) { *json = apr_psprintf(req->pool, "%s%s\"%.*s\":{\"authenticated\":%s," "\"complete\":%s," "\"values\":[", *json, (first ? "" : ","), (int)attr->name.length, (char *)attr->name.value, attr->authenticated ? "true" : "false", attr->complete ? "true" : "false"); } else { vstart = ","; } if (b64value) { if (len) { vformat = "%s%s{\"raw\":\"%s\",\"display\":\"%.*s\"}%s"; } else { vformat = "%s%s{\"raw\":\"%s\",\"display\":%.*s}%s"; } } else { if (len) { vformat = "%s%s{\"raw\":%s,\"display\":\"%.*s\"}%s"; } else { vformat = "%s%s{\"raw\":%s,\"display\":%.*s}%s"; } } if (attr->more == 0) { vend = "]}"; } *json = apr_psprintf(req->pool, vformat, *json, vstart, b64value ? b64value : "null", len ? len : 4, len ? value : "null", vend); } gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; void mag_get_name_attributes(request_rec *req, struct mag_config *cfg, gss_name_t name, struct mag_conn *mc) { if (!cfg->name_attributes) { return; } uint32_t maj, min; gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; struct name_attr attr; char *json = NULL; char *error; int count = 0; int i, j; maj = gss_inquire_name(&min, name, NULL, NULL, &attrs); if (GSS_ERROR(maj)) { error = mag_error(req, "gss_inquire_name() failed", maj, min); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", error); apr_table_set(req->subprocess_env, "GSS_NAME_ATTR_ERROR", error); return; } if (!attrs || attrs->count == 0) { mc_add_name_attribute(mc, "GSS_NAME_ATTR_ERROR", "0 attributes found"); } if (cfg->name_attributes->output_json) { if (attrs) count = attrs->count; json = apr_psprintf(req->pool, "{\"name\":\"%s\",\"attributes\":{", mc->gss_name); } else { count = cfg->name_attributes->map_count; } for (i = 0; i < count; i++) { memset(&attr, 0, sizeof(struct name_attr)); if (cfg->name_attributes->output_json) { attr.name = attrs->elements[i]; for (j = 0; j < cfg->name_attributes->map_count; j++) { if (strncmp(cfg->name_attributes->map[j].attr_name, attrs->elements[i].value, attrs->elements[i].length) == 0) { attr.env_name = cfg->name_attributes->map[j].env_name; break; } } } else { attr.name.length = strlen(cfg->name_attributes->map[i].attr_name); attr.name.value = cfg->name_attributes->map[i].attr_name; attr.env_name = cfg->name_attributes->map[i].env_name; } attr.number = 0; attr.more = -1; do { attr.number++; attr.value = empty_buffer; attr.display_value = empty_buffer; if (!mag_get_name_attr(req, name, &attr)) break; if (cfg->name_attributes->output_json) { mag_add_json_name_attr(req, i == 0, &attr, &json); } if (attr.env_name) { mag_set_env_name_attr(req, mc, &attr); } gss_release_buffer(&min, &attr.value); gss_release_buffer(&min, &attr.display_value); } while (attr.more != 0); } if (cfg->name_attributes->output_json) { json = apr_psprintf(req->pool, "%s}}", json); mc_add_name_attribute(mc, "GSS_NAME_ATTRS_JSON", json); } } static void mag_set_name_attributes(request_rec *req, struct mag_conn *mc) { for (int i = 0; i < mc->na_count; i++) { apr_table_set(req->subprocess_env, mc->name_attributes[i].name, mc->name_attributes[i].value); } } 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); } void mag_set_req_data(request_rec *req, struct mag_config *cfg, struct mag_conn *mc) { apr_table_set(req->subprocess_env, "GSS_NAME", mc->gss_name); apr_table_set(req->subprocess_env, "GSS_SESSION_EXPIRATION", apr_psprintf(req->pool, "%ld", (long)mc->expiration)); req->ap_auth_type = apr_pstrdup(req->pool, mag_str_auth_type(mc->auth_type)); req->user = apr_pstrdup(req->pool, mc->user_name); if (mc->name_attributes) { mag_set_name_attributes(req, mc); } #ifdef HAVE_CRED_STORE 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); } } #endif } mod_auth_gssapi-1.3.2/src/environ.h000066400000000000000000000006731266122234600173150ustar00rootroot00000000000000/* Copyright (C) 2015 mod_auth_gssapi authors - See COPYING for (C) terms */ struct mag_config; struct mag_conn; void mag_get_name_attributes(request_rec *req, struct mag_config *cfg, gss_name_t name, struct mag_conn *mc); void mag_set_req_data(request_rec *req, struct mag_config *cfg, struct mag_conn *mc); mod_auth_gssapi-1.3.2/src/mod_auth_gssapi.c000066400000000000000000001334701266122234600210000ustar00rootroot00000000000000/* MOD AUTH GSSAPI Copyright (C) 2014 Simo Sorce Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mod_auth_gssapi.h" const gss_OID_desc gss_mech_spnego = { 6, "\x2b\x06\x01\x05\x05\x02" }; #ifdef HAVE_GSSAPI_GSSAPI_NTLMSSP_H const gss_OID_desc gss_mech_ntlmssp_desc = { GSS_NTLMSSP_OID_LENGTH, GSS_NTLMSSP_OID_STRING }; gss_const_OID gss_mech_ntlmssp = &gss_mech_ntlmssp_desc; const gss_OID_set_desc gss_mech_set_ntlmssp_desc = { 1, discard_const(&gss_mech_ntlmssp_desc) }; gss_const_OID_set gss_mech_set_ntlmssp = &gss_mech_set_ntlmssp_desc; #else gss_OID gss_mech_ntlmssp = GSS_C_NO_OID; gss_OID_set gss_mech_set_ntlmssp = GSS_C_NO_OID_SET; #endif #define MOD_AUTH_GSSAPI_VERSION PACKAGE_NAME "/" PACKAGE_VERSION module AP_MODULE_DECLARE_DATA auth_gssapi_module; APLOG_USE_MODULE(auth_gssapi); static char *mag_status(request_rec *req, int type, uint32_t err) { uint32_t maj_ret, min_ret; gss_buffer_desc text; uint32_t msg_ctx; char *msg_ret; int len; msg_ret = NULL; msg_ctx = 0; do { maj_ret = gss_display_status(&min_ret, err, type, GSS_C_NO_OID, &msg_ctx, &text); if (maj_ret != GSS_S_COMPLETE) { return msg_ret; } len = text.length; if (msg_ret) { msg_ret = apr_psprintf(req->pool, "%s, %*s", msg_ret, len, (char *)text.value); } else { msg_ret = apr_psprintf(req->pool, "%*s", len, (char *)text.value); } gss_release_buffer(&min_ret, &text); } while (msg_ctx != 0); return msg_ret; } char *mag_error(request_rec *req, const char *msg, uint32_t maj, uint32_t min) { char *msg_maj; char *msg_min; msg_maj = mag_status(req, GSS_C_GSS_CODE, maj); msg_min = mag_status(req, GSS_C_MECH_CODE, min); return apr_psprintf(req->pool, "%s: [%s (%s)]", msg, msg_maj, msg_min); } static APR_OPTIONAL_FN_TYPE(ssl_is_https) *mag_is_https = NULL; static int mag_post_config(apr_pool_t *cfgpool, apr_pool_t *log, apr_pool_t *temp, server_rec *s) { /* FIXME: create mutex to deal with connections and contexts ? */ mag_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); mag_post_config_session(); ap_add_version_component(cfgpool, MOD_AUTH_GSSAPI_VERSION); return OK; } static int mag_pre_connection(conn_rec *c, void *csd) { struct mag_conn *mc; mc = mag_new_conn_ctx(c->pool); mc->is_preserved = true; ap_set_module_config(c->conn_config, &auth_gssapi_module, (void*)mc); return OK; } static apr_status_t mag_conn_destroy(void *ptr) { struct mag_conn *mc = (struct mag_conn *)ptr; uint32_t min; if (mc->ctx) { (void)gss_delete_sec_context(&min, &mc->ctx, GSS_C_NO_BUFFER); } return APR_SUCCESS; } struct mag_conn *mag_new_conn_ctx(apr_pool_t *pool) { struct mag_conn *mc; mc = apr_pcalloc(pool, sizeof(struct mag_conn)); apr_pool_create(&mc->pool, pool); /* register the context in the memory pool, so it can be freed * when the connection/request is terminated */ apr_pool_cleanup_register(mc->pool, (void *)mc, mag_conn_destroy, apr_pool_cleanup_null); return mc; } static void mag_conn_clear(struct mag_conn *mc) { (void)mag_conn_destroy(mc); apr_pool_t *temp; apr_pool_clear(mc->pool); temp = mc->pool; memset(mc, 0, sizeof(struct mag_conn)); mc->pool = temp; } static bool mag_conn_is_https(conn_rec *c) { if (mag_is_https) { if (mag_is_https(c)) return true; } return false; } static bool mag_acquire_creds(request_rec *req, struct mag_config *cfg, gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t *creds, gss_OID_set *actual_mechs) { uint32_t maj, min; #ifdef HAVE_CRED_STORE gss_const_key_value_set_t store = cfg->cred_store; maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE, desired_mechs, cred_usage, store, creds, actual_mechs, NULL); #else maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE, desired_mechs, cred_usage, creds, actual_mechs, NULL); #endif if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_acquire_cred[_from]() " "failed to get server creds", maj, min)); return false; } return true; } #ifdef HAVE_CRED_STORE static char *escape(apr_pool_t *pool, const char *name, char find, const char *replace) { char *escaped = NULL; char *namecopy; char *n; char *p; namecopy = apr_pstrdup(pool, name); p = strchr(namecopy, find); if (!p) return namecopy; /* first segment */ n = namecopy; while (p) { /* terminate previous segment */ *p = '\0'; if (escaped) { escaped = apr_pstrcat(pool, escaped, n, replace, NULL); } else { escaped = apr_pstrcat(pool, n, replace, NULL); } /* move to next segment */ n = p + 1; p = strchr(n, find); } /* append last segment if any */ if (*n) { escaped = apr_pstrcat(pool, escaped, n, NULL); } return escaped; } char *mag_gss_name_to_ccache_name(request_rec *req, char *dir, const char *gss_name) { 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, gss_name, '~', "~~"); /* then escape away the separator (/) if any */ escaped = escape(req->pool, escaped, '/', "~"); return apr_psprintf(req->pool, "%s/%s", dir, escaped); } static void mag_store_deleg_creds(request_rec *req, char *dir, const char *gss_name, gss_cred_id_t delegated_cred) { gss_key_value_element_desc element; gss_key_value_set_desc store; char *ccname; uint32_t maj, min; element.key = "ccache"; store.elements = &element; store.count = 1; ccname = mag_gss_name_to_ccache_name(req, dir, gss_name); 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)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "failed to store delegated creds", maj, min)); } } #endif static bool parse_auth_header(apr_pool_t *pool, const char **auth_header, gss_buffer_t value) { char *auth_header_value; auth_header_value = ap_getword_white(pool, auth_header); if (!auth_header_value) return false; value->length = apr_base64_decode_len(auth_header_value) + 1; value->value = apr_pcalloc(pool, value->length); if (!value->value) return false; value->length = apr_base64_decode(value->value, auth_header_value); return true; } static bool is_mech_allowed(gss_OID_set allowed_mechs, gss_const_OID mech, bool multi_step_supported) { if (mech == GSS_C_NO_OID) return false; if (!multi_step_supported && gss_oid_equal(gss_mech_ntlmssp, mech)) return false; if (allowed_mechs == GSS_C_NO_OID_SET) return true; for (int i = 0; i < allowed_mechs->count; i++) { if (gss_oid_equal(&allowed_mechs->elements[i], mech)) { return true; } } return false; } #define AUTH_TYPE_NEGOTIATE 0 #define AUTH_TYPE_BASIC 1 #define AUTH_TYPE_RAW_NTLM 2 const char *auth_types[] = { "Negotiate", "Basic", "NTLM", NULL }; const char *mag_str_auth_type(int auth_type) { return auth_types[auth_type]; } gss_OID_set mag_filter_unwanted_mechs(gss_OID_set src) { gss_const_OID unwanted_mechs[] = { &gss_mech_spnego, gss_mech_krb5_old, gss_mech_krb5_wrong, gss_mech_iakerb, GSS_C_NO_OID }; gss_OID_set dst; uint32_t maj, min; int present = 0; if (src == GSS_C_NO_OID_SET) return GSS_C_NO_OID_SET; for (int i = 0; unwanted_mechs[i] != GSS_C_NO_OID; i++) { maj = gss_test_oid_set_member(&min, discard_const(unwanted_mechs[i]), src, &present); if (present) break; } if (present) { maj = gss_create_empty_oid_set(&min, &dst); if (maj != GSS_S_COMPLETE) { return GSS_C_NO_OID_SET; } for (int i = 0; i < src->count; i++) { present = 0; for (int j = 0; unwanted_mechs[j] != GSS_C_NO_OID; j++) { if (gss_oid_equal(&src->elements[i], unwanted_mechs[j])) { present = 1; break; } } if (present) continue; maj = gss_add_oid_set_member(&min, &src->elements[i], &dst); if (maj != GSS_S_COMPLETE) { gss_release_oid_set(&min, &dst); return GSS_C_NO_OID_SET; } } return dst; } return src; } static bool mag_auth_basic(request_rec *req, struct mag_config *cfg, gss_buffer_desc ba_user, gss_buffer_desc ba_pwd, gss_name_t *client, gss_OID *mech_type, gss_cred_id_t *delegated_cred, uint32_t *vtime) { #ifdef HAVE_GSS_KRB5_CCACHE_NAME const char *user_ccache = NULL; const char *orig_ccache = NULL; long long unsigned int rndname; apr_status_t rs; #endif gss_name_t user = GSS_C_NO_NAME; gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t user_ctx = GSS_C_NO_CONTEXT; gss_name_t server = GSS_C_NO_NAME; gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t server_ctx = GSS_C_NO_CONTEXT; gss_buffer_desc input = GSS_C_EMPTY_BUFFER; gss_buffer_desc output = GSS_C_EMPTY_BUFFER; gss_OID_set allowed_mechs; gss_OID_set filtered_mechs; gss_OID_set actual_mechs = GSS_C_NO_OID_SET; uint32_t init_flags = 0; uint32_t maj, min; int present = 0; bool ret = false; maj = gss_import_name(&min, &ba_user, GSS_C_NT_USER_NAME, &user); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_import_name() failed", maj, min)); goto done; } if (cfg->basic_mechs) { allowed_mechs = cfg->basic_mechs; } else if (cfg->allowed_mechs) { allowed_mechs = cfg->allowed_mechs; } else { struct mag_server_config *scfg; /* Try to fetch the default set if not explicitly configured, * We need to do this because gss_acquire_cred_with_password() * is currently limited to acquire creds for a single "default" * mechanism if no desired mechanisms are passed in. This causes * authentication to fail for secondary mechanisms as no user * credentials are generated for those. */ scfg = ap_get_module_config(req->server->module_config, &auth_gssapi_module); /* In the worst case scenario default_mechs equals to GSS_C_NO_OID_SET. * This generally causes only the krb5 mechanism to be tried due * to implementation constraints, but may change in future. */ allowed_mechs = scfg->default_mechs; } /* Remove Spnego if present, or we'd repeat failed authentiations * multiple times, one within Spnego and then again with an explicit * mechanism. We would normally just force Spnego and use * gss_set_neg_mechs, but due to the way we source the server name * and the fact MIT up to 1.14 at least does no handle union names, * we can't provide spnego with a server name that can be used by * multiple mechanisms, causing any but the first mechanism to fail. * Also remove unwanted krb mechs, or AS requests will be repeated * multiple times uselessly. */ filtered_mechs = mag_filter_unwanted_mechs(allowed_mechs); if (filtered_mechs == allowed_mechs) { /* in case filtered_mechs was not allocated here don't free it */ filtered_mechs = GSS_C_NO_OID_SET; } else if (filtered_mechs == GSS_C_NO_OID_SET) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "Fatal " "failure while filtering mechs, aborting"); goto done; } else { /* use the filtered list */ allowed_mechs = filtered_mechs; } #ifdef HAVE_GSS_KRB5_CCACHE_NAME /* If we are using the krb5 mechanism make sure to set a per thread * memory ccache so that there can't be interferences between threads. * Also make sure we have new cache so no cached results end up being * used. Some implementations of gss_acquire_cred_with_password() do * not reacquire creds if cached ones are around, failing to check * again for the password. */ maj = gss_test_oid_set_member(&min, discard_const(gss_mech_krb5), allowed_mechs, &present); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_test_oid_set_member() failed", maj, min)); goto done; } if (present) { rs = apr_generate_random_bytes((unsigned char *)(&rndname), sizeof(long long unsigned int)); if (rs != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "Failed to generate random ccache name"); goto done; } user_ccache = apr_psprintf(req->pool, "MEMORY:user_%qu", rndname); maj = gss_krb5_ccache_name(&min, user_ccache, &orig_ccache); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_krb5_ccache_name() " "failed", maj, min)); goto done; } } #endif maj = gss_acquire_cred_with_password(&min, user, &ba_pwd, GSS_C_INDEFINITE, allowed_mechs, GSS_C_INITIATE, &user_cred, &actual_mechs, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "In Basic Auth, %s", mag_error(req, "gss_acquire_cred_with_password() " "failed", maj, min)); goto done; } /* must acquire creds based on the actual mechs we want to try */ if (!mag_acquire_creds(req, cfg, actual_mechs, GSS_C_ACCEPT, &server_cred, NULL)) { goto done; } #ifdef HAVE_CRED_STORE if (cfg->deleg_ccache_dir) { /* delegate ourselves credentials so we store them as requested */ init_flags |= GSS_C_DELEG_FLAG; } #endif for (int i = 0; i < actual_mechs->count; i++) { /* free these if looping */ gss_release_buffer(&min, &output); gss_release_buffer(&min, &input); gss_release_name(&min, &server); maj = gss_inquire_cred_by_mech(&min, server_cred, &actual_mechs->elements[i], &server, NULL, NULL, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_inquired_cred_by_mech() " "failed", maj, min)); continue; } do { /* output and input are inverted here, this is intentional */ maj = gss_init_sec_context(&min, user_cred, &user_ctx, server, &actual_mechs->elements[i], init_flags, 300, GSS_C_NO_CHANNEL_BINDINGS, &output, NULL, &input, NULL, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_init_sec_context() " "failed", maj, min)); break; } gss_release_buffer(&min, &output); maj = gss_accept_sec_context(&min, &server_ctx, server_cred, &input, GSS_C_NO_CHANNEL_BINDINGS, client, mech_type, &output, NULL, vtime, delegated_cred); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_accept_sec_context()" " failed", maj, min)); break; } gss_release_buffer(&min, &input); } while (maj == GSS_S_CONTINUE_NEEDED); if (maj == GSS_S_COMPLETE) { ret = true; break; } } done: gss_release_buffer(&min, &output); gss_release_buffer(&min, &input); gss_release_name(&min, &server); gss_delete_sec_context(&min, &server_ctx, GSS_C_NO_BUFFER); gss_release_cred(&min, &server_cred); gss_release_name(&min, &user); gss_release_cred(&min, &user_cred); gss_delete_sec_context(&min, &user_ctx, GSS_C_NO_BUFFER); gss_release_oid_set(&min, &actual_mechs); gss_release_oid_set(&min, &filtered_mechs); #ifdef HAVE_GSS_KRB5_CCACHE_NAME if (user_ccache != NULL) { maj = gss_krb5_ccache_name(&min, orig_ccache, NULL); if (maj != GSS_S_COMPLETE) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "Failed to restore per-thread ccache, %s", mag_error(req, "gss_krb5_ccache_name() " "failed", maj, min)); } } #endif return ret; } struct mag_req_cfg *mag_init_cfg(request_rec *req) { struct mag_server_config *scfg; struct mag_req_cfg *req_cfg = apr_pcalloc(req->pool, sizeof(struct mag_req_cfg)); req_cfg->req = req; req_cfg->cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module); scfg = ap_get_module_config(req->server->module_config, &auth_gssapi_module); if (req_cfg->cfg->allowed_mechs) { req_cfg->desired_mechs = req_cfg->cfg->allowed_mechs; } else { /* Use the default set if not explicitly configured */ req_cfg->desired_mechs = scfg->default_mechs; } if (req_cfg->cfg->mag_skey) { req_cfg->mag_skey = req_cfg->cfg->mag_skey; } else { /* Use server random key if not explicitly configured */ req_cfg->mag_skey = scfg->mag_skey; } if (req->proxyreq == PROXYREQ_PROXY) { req_cfg->req_proto = "Proxy-Authorization"; req_cfg->rep_proto = "Proxy-Authenticate"; } else { req_cfg->req_proto = "Authorization"; req_cfg->rep_proto = "WWW-Authenticate"; req_cfg->use_sessions = req_cfg->cfg->use_sessions; req_cfg->send_persist = req_cfg->cfg->send_persist; } return req_cfg; } #ifdef HAVE_CRED_STORE static bool use_s4u2proxy(struct mag_req_cfg *req_cfg) { if (req_cfg->cfg->use_s4u2proxy) { if (req_cfg->cfg->deleg_ccache_dir != NULL) { return true; } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req_cfg->req, "S4U2 Proxy requested but GssapiDelegCcacheDir " "is not set. Constrained delegation disabled!"); } } return false; } #endif static int mag_auth(request_rec *req) { const char *type; int auth_type = -1; struct mag_req_cfg *req_cfg; struct mag_config *cfg; const char *auth_header; char *auth_header_type; int ret = HTTP_UNAUTHORIZED; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_ctx_id_t *pctx; gss_buffer_desc input = GSS_C_EMPTY_BUFFER; gss_buffer_desc output = GSS_C_EMPTY_BUFFER; gss_buffer_desc name = GSS_C_EMPTY_BUFFER; gss_buffer_desc ba_user; gss_buffer_desc ba_pwd; gss_name_t client = GSS_C_NO_NAME; gss_cred_id_t acquired_cred = GSS_C_NO_CREDENTIAL; gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL; gss_cred_usage_t cred_usage = GSS_C_ACCEPT; uint32_t vtime; uint32_t maj, min; char *reply; size_t replen; gss_OID mech_type = GSS_C_NO_OID; gss_OID_set desired_mechs = GSS_C_NO_OID_SET; gss_buffer_desc lname = GSS_C_EMPTY_BUFFER; struct mag_conn *mc = NULL; int i; bool send_auth_header = true; type = ap_auth_type(req); if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) { return DECLINED; } req_cfg = mag_init_cfg(req); cfg = req_cfg->cfg; desired_mechs = req_cfg->desired_mechs; /* implicit auth for subrequests if main auth already happened */ if (!ap_is_initial_req(req) && req->main != NULL) { type = ap_auth_type(req->main); if ((type != NULL) && (strcasecmp(type, "GSSAPI") == 0)) { /* warn if the subrequest location and the main request * location have different configs */ if (cfg != ap_get_module_config(req->main->per_dir_config, &auth_gssapi_module)) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "Subrequest authentication bypass on " "location with different configuration!"); } if (req->main->user) { req->user = apr_pstrdup(req->pool, req->main->user); return OK; } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "The main request is tasked to establish the " "security context, can't proceed!"); return HTTP_UNAUTHORIZED; } } else { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req, "Subrequest GSSAPI auth with no auth on the main " "request. This operation may fail if other " "subrequests already established a context or the " "mechanism requires multiple roundtrips."); } } if (cfg->ssl_only) { if (!mag_conn_is_https(req->connection)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "Not a TLS connection, refusing to authenticate!"); goto done; } } if (cfg->gss_conn_ctx) { mc = (struct mag_conn *)ap_get_module_config( req->connection->conn_config, &auth_gssapi_module); if (!mc) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req, "Failed to retrieve connection context!"); goto done; } } /* if available, session always supersedes connection bound data */ if (req_cfg->use_sessions) { mag_check_session(req_cfg, &mc); } auth_header = apr_table_get(req->headers_in, req_cfg->req_proto); if (mc) { if (mc->established && (auth_header == NULL) && (mc->auth_type != AUTH_TYPE_BASIC)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req, "Already established context found!"); mag_set_req_data(req, cfg, mc); ret = OK; goto done; } pctx = &mc->ctx; } else { /* no preserved mc, create one just for this request */ mc = mag_new_conn_ctx(req->pool); pctx = &ctx; } /* We can proceed only if we do have an auth header */ if (!auth_header) goto done; auth_header_type = ap_getword_white(req->pool, &auth_header); if (!auth_header_type) goto done; /* We got auth header, sending auth header would mean re-auth */ send_auth_header = !cfg->negotiate_once; for (i = 0; auth_types[i] != NULL; i++) { if (strcasecmp(auth_header_type, auth_types[i]) == 0) { auth_type = i; break; } } switch (auth_type) { case AUTH_TYPE_NEGOTIATE: if (!parse_auth_header(req->pool, &auth_header, &input)) { goto done; } break; case AUTH_TYPE_BASIC: if (!cfg->use_basic_auth) { goto done; } ba_pwd.value = ap_pbase64decode(req->pool, auth_header); if (!ba_pwd.value) goto done; ba_user.value = ap_getword_nulls_nc(req->pool, (char **)&ba_pwd.value, ':'); if (!ba_user.value) goto done; if (((char *)ba_user.value)[0] == '\0' || ((char *)ba_pwd.value)[0] == '\0') { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "Invalid empty user or password for Basic Auth"); goto done; } ba_user.length = strlen(ba_user.value); ba_pwd.length = strlen(ba_pwd.value); if (mc->is_preserved && mc->established && mag_basic_check(req_cfg, mc, ba_user, ba_pwd)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req, "Already established BASIC AUTH context found!"); mag_set_req_data(req, cfg, mc); ret = OK; goto done; } break; case AUTH_TYPE_RAW_NTLM: if (!is_mech_allowed(desired_mechs, gss_mech_ntlmssp, cfg->gss_conn_ctx)) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req, "NTLM Authentication is not allowed!"); goto done; } if (!parse_auth_header(req->pool, &auth_header, &input)) { goto done; } desired_mechs = discard_const(gss_mech_set_ntlmssp); break; default: goto done; } if (mc->established) { /* if we are re-authenticating make sure the conn context * is cleaned up so we do not accidentally reuse an existing * established context */ mag_conn_clear(mc); } mc->auth_type = auth_type; #ifdef HAVE_CRED_STORE if (use_s4u2proxy(req_cfg)) { cred_usage = GSS_C_BOTH; } #endif if (auth_type == AUTH_TYPE_BASIC) { if (mag_auth_basic(req, cfg, ba_user, ba_pwd, &client, &mech_type, &delegated_cred, &vtime)) { goto complete; } goto done; } if (!mag_acquire_creds(req, cfg, desired_mechs, cred_usage, &acquired_cred, NULL)) { goto done; } if (auth_type == AUTH_TYPE_NEGOTIATE && cfg->allowed_mechs != GSS_C_NO_OID_SET) { maj = gss_set_neg_mechs(&min, acquired_cred, cfg->allowed_mechs); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_set_neg_mechs() failed", maj, min)); goto done; } } maj = gss_accept_sec_context(&min, pctx, acquired_cred, &input, GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_type, &output, NULL, &vtime, &delegated_cred); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_accept_sec_context() failed", maj, min)); goto done; } else if (maj == GSS_S_CONTINUE_NEEDED) { if (!mc->is_preserved) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "Mechanism needs continuation but neither " "GssapiConnectionBound nor " "GssapiUseSessions are available"); gss_release_buffer(&min, &output); output.length = 0; } /* auth not complete send token and wait next packet */ goto done; } complete: maj = gss_display_name(&min, client, &name, NULL); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_display_name() failed", maj, min)); goto done; } mc->gss_name = apr_pstrndup(req->pool, name.value, name.length); if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) { vtime = MIN_SESS_EXP_TIME; } mc->expiration = time(NULL) + vtime; mag_get_name_attributes(req, cfg, client, mc); #ifdef HAVE_CRED_STORE if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) { mag_store_deleg_creds(req, cfg->deleg_ccache_dir, mc->gss_name, delegated_cred); mc->delegated = true; } #endif if (cfg->map_to_local) { maj = gss_localname(&min, client, mech_type, &lname); if (maj != GSS_S_COMPLETE) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", mag_error(req, "gss_localname() failed", maj, min)); goto done; } mc->user_name = apr_pstrndup(req->pool, lname.value, lname.length); } else { mc->user_name = apr_pstrdup(mc->pool, mc->gss_name); } mc->established = true; if (auth_type == AUTH_TYPE_BASIC) { mag_basic_cache(req_cfg, mc, ba_user, ba_pwd); } if (req_cfg->use_sessions) { mag_attempt_session(req_cfg, mc); } /* Now set request data and env vars */ mag_set_req_data(req, cfg, mc); if (req_cfg->send_persist) apr_table_set(req->headers_out, "Persistent-Auth", cfg->gss_conn_ctx ? "true" : "false"); ret = OK; done: if ((auth_type != AUTH_TYPE_BASIC) && (output.length != 0)) { int prefixlen = strlen(mag_str_auth_type(auth_type)) + 1; replen = apr_base64_encode_len(output.length) + 1; reply = apr_pcalloc(req->pool, prefixlen + replen); if (reply) { memcpy(reply, mag_str_auth_type(auth_type), prefixlen - 1); reply[prefixlen - 1] = ' '; apr_base64_encode(&reply[prefixlen], output.value, output.length); apr_table_add(req->err_headers_out, req_cfg->rep_proto, reply); } } else if (ret == HTTP_UNAUTHORIZED) { if (send_auth_header) { apr_table_add(req->err_headers_out, req_cfg->rep_proto, "Negotiate"); if (is_mech_allowed(desired_mechs, gss_mech_ntlmssp, cfg->gss_conn_ctx)) { apr_table_add(req->err_headers_out, req_cfg->rep_proto, "NTLM"); } } if (cfg->use_basic_auth) { apr_table_add(req->err_headers_out, req_cfg->rep_proto, apr_psprintf(req->pool, "Basic realm=\"%s\"", ap_auth_name(req))); } } if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER); gss_release_cred(&min, &acquired_cred); gss_release_cred(&min, &delegated_cred); gss_release_buffer(&min, &output); gss_release_name(&min, &client); gss_release_buffer(&min, &name); gss_release_buffer(&min, &lname); return ret; } static void *mag_create_dir_config(apr_pool_t *p, char *dir) { struct mag_config *cfg; cfg = (struct mag_config *)apr_pcalloc(p, sizeof(struct mag_config)); cfg->pool = p; return cfg; } static const char *mag_ssl_only(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->ssl_only = on ? true : false; return NULL; } static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->map_to_local = on ? true : false; return NULL; } static const char *mag_conn_ctx(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->gss_conn_ctx = on ? true : false; return NULL; } static const char *mag_send_persist(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->send_persist = on ? true : false; return NULL; } static const char *mag_use_sess(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->use_sessions = on ? true : false; return NULL; } #ifdef HAVE_CRED_STORE static const char *mag_use_s4u2p(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->use_s4u2proxy = on ? true : false; return NULL; } #endif static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w) { struct mag_config *cfg = (struct mag_config *)mconfig; struct databuf keys; unsigned char *val; apr_status_t rc; const char *k; int l; if (strncmp(w, "key:", 4) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "Invalid key format, expected prefix 'key:'"); return NULL; } k = w + 4; l = apr_base64_decode_len(k); val = apr_palloc(parms->temp_pool, l); keys.length = (int)apr_base64_decode_binary(val, k); keys.value = (unsigned char *)val; if (keys.length != 32) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "Invalid key length, expected 32 got %d", keys.length); return NULL; } rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, &keys); if (rc != OK) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "Failed to import sealing key!"); } return NULL; } #ifdef HAVE_CRED_STORE #define MAX_CRED_OPTIONS 10 static const char *mag_cred_store(cmd_parms *parms, void *mconfig, const char *w) { struct mag_config *cfg = (struct mag_config *)mconfig; gss_key_value_element_desc *elements; uint32_t count; size_t size; const char *p; char *value; char *key; p = strchr(w, ':'); if (!p) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "%s [%s]", "Invalid syntax for GssapiCredStore option", w); return NULL; } key = apr_pstrndup(parms->pool, w, (p-w)); value = apr_pstrdup(parms->pool, p + 1); if (!cfg->cred_store) { cfg->cred_store = apr_pcalloc(parms->pool, sizeof(gss_key_value_set_desc)); size = sizeof(gss_key_value_element_desc) * MAX_CRED_OPTIONS; cfg->cred_store->elements = apr_palloc(parms->pool, size); } elements = cfg->cred_store->elements; count = cfg->cred_store->count; if (count >= MAX_CRED_OPTIONS) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "Too many GssapiCredStore options (MAX: %d)", MAX_CRED_OPTIONS); return NULL; } cfg->cred_store->count++; elements[count].key = key; elements[count].value = value; return NULL; } static const char *mag_deleg_ccache_dir(cmd_parms *parms, void *mconfig, const char *value) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->deleg_ccache_dir = apr_pstrdup(parms->pool, value); return NULL; } #endif #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD static const char *mag_use_basic_auth(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->use_basic_auth = on ? true : false; return NULL; } #endif static apr_status_t mag_oid_set_destroy(void *ptr) { uint32_t min; gss_OID_set set = (gss_OID_set)ptr; (void)gss_release_oid_set(&min, &set); return APR_SUCCESS; } static bool mag_list_of_mechs(cmd_parms *parms, gss_OID_set *oidset, bool add_spnego, const char *w) { gss_buffer_desc buf = { 0 }; uint32_t maj, min; gss_OID_set set; gss_OID oid; bool release_oid = false; if (NULL == *oidset) { maj = gss_create_empty_oid_set(&min, &set); if (maj != GSS_S_COMPLETE) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "gss_create_empty_oid_set() failed."); *oidset = GSS_C_NO_OID_SET; return false; } if (add_spnego) { oid = discard_const(&gss_mech_spnego); maj = gss_add_oid_set_member(&min, oid, &set); if (maj != GSS_S_COMPLETE) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "gss_add_oid_set_member() failed."); (void)gss_release_oid_set(&min, &set); *oidset = GSS_C_NO_OID_SET; return false; } } /* register in the pool so it can be released once the server * winds down */ apr_pool_cleanup_register(parms->pool, (void *)set, mag_oid_set_destroy, apr_pool_cleanup_null); *oidset = set; } else { set = *oidset; } if (strcmp(w, "krb5") == 0) { oid = discard_const(gss_mech_krb5); } else if (strcmp(w, "iakerb") == 0) { oid = discard_const(gss_mech_iakerb); } else if (strcmp(w, "ntlmssp") == 0) { oid = discard_const(gss_mech_ntlmssp); } else { buf.value = discard_const(w); buf.length = strlen(w); maj = gss_str_to_oid(&min, &buf, &oid); if (maj != GSS_S_COMPLETE) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "Unrecognized GSSAPI Mechanism: [%s]", w); return false; } release_oid = true; } maj = gss_add_oid_set_member(&min, oid, &set); if (maj != GSS_S_COMPLETE) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "gss_add_oid_set_member() failed for [%s].", w); } if (release_oid) { (void)gss_release_oid(&min, &oid); } return true; } static const char *mag_allow_mech(cmd_parms *parms, void *mconfig, const char *w) { struct mag_config *cfg = (struct mag_config *)mconfig; if (!mag_list_of_mechs(parms, &cfg->allowed_mechs, true, w)) return "Failed to apply GssapiAllowedMech directive"; return NULL; } static const char *mag_negotiate_once(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; cfg->negotiate_once = on ? true : false; return NULL; } #define GSS_NAME_ATTR_USERDATA "GSS Name Attributes Userdata" static apr_status_t mag_name_attrs_cleanup(void *data) { struct mag_config *cfg = (struct mag_config *)data; free(cfg->name_attributes); cfg->name_attributes = NULL; return 0; } static const char *mag_name_attrs(cmd_parms *parms, void *mconfig, const char *w) { struct mag_config *cfg = (struct mag_config *)mconfig; void *tmp_na; size_t size = 0; char *p; int c; if (!cfg->name_attributes) { size = sizeof(struct mag_name_attributes) + (sizeof(struct mag_na_map) * 16); } else if (cfg->name_attributes->map_count % 16 == 0) { size = sizeof(struct mag_name_attributes) + (sizeof(struct mag_na_map) * (cfg->name_attributes->map_count + 16)); } if (size) { tmp_na = realloc(cfg->name_attributes, size); if (!tmp_na) apr_pool_abort_get(cfg->pool)(ENOMEM); if (cfg->name_attributes) { size_t empty = (sizeof(struct mag_na_map) * 16); memset(tmp_na + size - empty, 0, empty); } else { memset(tmp_na, 0, size); } cfg->name_attributes = (struct mag_name_attributes *)tmp_na; apr_pool_userdata_setn(cfg, GSS_NAME_ATTR_USERDATA, mag_name_attrs_cleanup, cfg->pool); } p = strchr(w, ' '); if (p == NULL) { if (strcmp(w, "json") == 0) { cfg->name_attributes->output_json = true; } else { ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, "Invalid Name Attributes value [%s].", w); } return NULL; } c = cfg->name_attributes->map_count; cfg->name_attributes->map[c].env_name = apr_pstrndup(cfg->pool, w, p-w); p++; cfg->name_attributes->map[c].attr_name = apr_pstrdup(cfg->pool, p); cfg->name_attributes->map_count += 1; return NULL; } #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD static const char *mag_basic_auth_mechs(cmd_parms *parms, void *mconfig, const char *w) { struct mag_config *cfg = (struct mag_config *)mconfig; if (!mag_list_of_mechs(parms, &cfg->basic_mechs, false, w)) return "Failed to apply GssapiBasicAuthMech directive"; return NULL; } #endif static void *mag_create_server_config(apr_pool_t *p, server_rec *s) { struct mag_server_config *scfg; uint32_t maj, min; apr_status_t rc; scfg = apr_pcalloc(p, sizeof(struct mag_server_config)); maj = gss_indicate_mechs(&min, &scfg->default_mechs); if (maj != GSS_S_COMPLETE) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "gss_indicate_mechs() failed"); } else { /* Register the set in pool */ apr_pool_cleanup_register(p, (void *)scfg->default_mechs, mag_oid_set_destroy, apr_pool_cleanup_null); } rc = SEAL_KEY_CREATE(p, &scfg->mag_skey, NULL); if (rc != OK) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Failed to generate random sealing key!"); } return scfg; } static const command_rec mag_commands[] = { AP_INIT_FLAG("GssapiSSLonly", mag_ssl_only, NULL, OR_AUTHCFG, "Work only if connection is SSL Secured"), AP_INIT_FLAG("GssapiLocalName", mag_map_to_local, NULL, OR_AUTHCFG, "Translate principals to local names"), AP_INIT_FLAG("GssapiConnectionBound", mag_conn_ctx, NULL, OR_AUTHCFG, "Authentication is bound to the TCP connection"), AP_INIT_FLAG("GssapiSignalPersistentAuth", mag_send_persist, NULL, OR_AUTHCFG, "Send Persitent-Auth header according to connection bound"), AP_INIT_FLAG("GssapiUseSessions", mag_use_sess, NULL, OR_AUTHCFG, "Authentication uses mod_sessions to hold status"), AP_INIT_RAW_ARGS("GssapiSessionKey", mag_sess_key, NULL, OR_AUTHCFG, "Key Used to seal session data."), #ifdef HAVE_CRED_STORE AP_INIT_FLAG("GssapiUseS4U2Proxy", mag_use_s4u2p, NULL, OR_AUTHCFG, "Initializes credentials for s4u2proxy usage"), AP_INIT_ITERATE("GssapiCredStore", mag_cred_store, NULL, OR_AUTHCFG, "Credential Store"), AP_INIT_RAW_ARGS("GssapiDelegCcacheDir", mag_deleg_ccache_dir, NULL, OR_AUTHCFG, "Directory to store delegated credentials"), #endif #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG, "Allows use of Basic Auth for authentication"), AP_INIT_ITERATE("GssapiBasicAuthMech", mag_basic_auth_mechs, NULL, OR_AUTHCFG, "Mechanisms to use for basic auth"), #endif AP_INIT_ITERATE("GssapiAllowedMech", mag_allow_mech, NULL, OR_AUTHCFG, "Allowed Mechanisms"), AP_INIT_FLAG("GssapiNegotiateOnce", mag_negotiate_once, NULL, OR_AUTHCFG, "Don't resend negotiate header on negotiate failure"), AP_INIT_RAW_ARGS("GssapiNameAttributes", mag_name_attrs, NULL, OR_AUTHCFG, "Name Attributes to be exported as environ variables"), { NULL } }; static void mag_register_hooks(apr_pool_t *p) { ap_hook_check_user_id(mag_auth, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(mag_post_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_pre_connection(mag_pre_connection, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA auth_gssapi_module = { STANDARD20_MODULE_STUFF, mag_create_dir_config, NULL, mag_create_server_config, NULL, mag_commands, mag_register_hooks }; mod_auth_gssapi-1.3.2/src/mod_auth_gssapi.h000066400000000000000000000053721266122234600210040ustar00rootroot00000000000000/* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */ #include #include #include #define APR_WANT_STRFUNC #include "apr_want.h" #include #include #include #include #include #include #include #include #include /* apache's httpd.h drags in empty PACKAGE_* variables. * undefine them to avoid annoying compile warnings as they * are re-defined in config.h */ #undef PACKAGE_BUGREPORT #undef PACKAGE_NAME #undef PACKAGE_STRING #undef PACKAGE_TARNAME #undef PACKAGE_VERSION #include "config.h" #include #include #include #ifdef HAVE_GSSAPI_GSSAPI_NTLMSSP_H # include #endif #include "crypto.h" #include "sessions.h" #include "environ.h" #define MIN_SESS_EXP_TIME 300 /* 5 minutes validity minimum */ #ifdef HAVE_GSS_ACQUIRE_CRED_FROM # ifdef HAVE_GSS_STORE_CRED_INTO #define HAVE_CRED_STORE 1 # endif #endif struct mag_na_map { char *env_name; char *attr_name; }; struct mag_name_attributes { bool output_json; int map_count; struct mag_na_map map[]; }; struct mag_config { apr_pool_t *pool; bool ssl_only; bool map_to_local; bool gss_conn_ctx; bool send_persist; bool use_sessions; #ifdef HAVE_CRED_STORE bool use_s4u2proxy; char *deleg_ccache_dir; gss_key_value_set_desc *cred_store; #endif struct seal_key *mag_skey; bool use_basic_auth; gss_OID_set_desc *allowed_mechs; gss_OID_set_desc *basic_mechs; bool negotiate_once; struct mag_name_attributes *name_attributes; }; struct mag_server_config { gss_OID_set default_mechs; struct seal_key *mag_skey; }; struct mag_req_cfg { request_rec *req; struct mag_config *cfg; gss_OID_set desired_mechs; bool use_sessions; bool send_persist; const char *req_proto; const char *rep_proto; struct seal_key *mag_skey; }; struct mag_attr { const char *name; const char *value; }; struct mag_conn { apr_pool_t *pool; gss_ctx_id_t ctx; bool established; const char *user_name; const char *gss_name; time_t expiration; int auth_type; bool delegated; struct databuf basic_hash; bool is_preserved; int na_count; struct mag_attr *name_attributes; }; #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) struct mag_conn *mag_new_conn_ctx(apr_pool_t *pool); const char *mag_str_auth_type(int auth_type); char *mag_gss_name_to_ccache_name(request_rec *req, char *dir, const char *gss_name); char *mag_error(request_rec *req, const char *msg, uint32_t maj, uint32_t min); mod_auth_gssapi-1.3.2/src/sessions.c000066400000000000000000000233641266122234600175000ustar00rootroot00000000000000/* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */ #include "mod_auth_gssapi.h" #include "asn1c/GSSSessionData.h" APLOG_USE_MODULE(auth_gssapi); static APR_OPTIONAL_FN_TYPE(ap_session_load) *mag_sess_load_fn = NULL; static APR_OPTIONAL_FN_TYPE(ap_session_get) *mag_sess_get_fn = NULL; static APR_OPTIONAL_FN_TYPE(ap_session_set) *mag_sess_set_fn = NULL; void mag_post_config_session(void) { mag_sess_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load); mag_sess_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get); mag_sess_set_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_set); } static apr_status_t mag_session_load(request_rec *req, session_rec **sess) { if (mag_sess_load_fn) { return mag_sess_load_fn(req, sess); } return DECLINED; } static apr_status_t mag_session_get(request_rec *req, session_rec *sess, const char *key, const char **value) { if (mag_sess_get_fn) { return mag_sess_get_fn(req, sess, key, value); } return DECLINED; } static apr_status_t mag_session_set(request_rec *req, session_rec *sess, const char *key, const char *value) { if (mag_sess_set_fn) { return mag_sess_set_fn(req, sess, key, value); } return DECLINED; } static bool encode_GSSSessionData(apr_pool_t *mempool, GSSSessionData_t *gsessdata, unsigned char **buf, int *len) { asn_enc_rval_t rval; unsigned char *buffer = NULL; size_t buflen; bool ret = false; /* dry run to compute the size */ rval = der_encode(&asn_DEF_GSSSessionData, gsessdata, NULL, NULL); if (rval.encoded == -1) goto done; buflen = rval.encoded; buffer = apr_pcalloc(mempool, buflen); /* now for real */ rval = der_encode_to_buffer(&asn_DEF_GSSSessionData, gsessdata, buffer, buflen); if (rval.encoded == -1) goto done; *buf = buffer; *len = buflen; ret = true; done: return ret; } static GSSSessionData_t *decode_GSSSessionData(void *buf, size_t len) { GSSSessionData_t *gsessdata = NULL; asn_dec_rval_t rval; rval = ber_decode(NULL, &asn_DEF_GSSSessionData, (void **)&gsessdata, buf, len); if (rval.code == RC_OK) { return gsessdata; } return NULL; } #define MAG_BEARER_KEY "MagBearerToken" void mag_check_session(struct mag_req_cfg *cfg, struct mag_conn **conn) { request_rec *req = cfg->req; struct mag_conn *mc; apr_status_t rc; session_rec *sess = NULL; const char *sessval = NULL; int declen; struct databuf ctxbuf = { 0 }; struct databuf cipherbuf = { 0 }; GSSSessionData_t *gsessdata; time_t expiration; rc = mag_session_load(req, &sess); if (rc != OK || sess == NULL) { ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, req, "Sessions not available, no cookies!"); return; } mc = *conn; if (!mc) { *conn = mc = mag_new_conn_ctx(req->pool); mc->is_preserved = true; } rc = mag_session_get(req, sess, MAG_BEARER_KEY, &sessval); if (rc != OK) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "Failed to get session data!"); return; } if (!sessval) { /* no session established, just return */ return; } if (!cfg->mag_skey) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req, "Session key not available, no cookies!"); /* we do not have a key, just return */ return; } /* decode it */ declen = apr_base64_decode_len(sessval); cipherbuf.value = apr_palloc(req->pool, declen); if (!cipherbuf.value) return; cipherbuf.length = (int)apr_base64_decode((char *)cipherbuf.value, sessval); rc = UNSEAL_BUFFER(req->pool, cfg->mag_skey, &cipherbuf, &ctxbuf); if (rc != OK) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "Failed to unseal session data!"); return; } gsessdata = decode_GSSSessionData(ctxbuf.value, ctxbuf.length); if (!gsessdata) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "Failed to unpack session data!"); 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)) { /* credentials fully expired, return nothing */ mc->established = false; goto done; } /* user name */ mc->user_name = apr_pstrndup(mc->pool, (char *)gsessdata->username.buf, gsessdata->username.size); if (!mc->user_name) goto done; /* gssapi name */ mc->gss_name = apr_pstrndup(mc->pool, (char *)gsessdata->gssname.buf, gsessdata->gssname.size); if (!mc->gss_name) goto done; mc->basic_hash.length = gsessdata->basichash.size; mc->basic_hash.value = apr_palloc(mc->pool, mc->basic_hash.length); memcpy(mc->basic_hash.value, gsessdata->basichash.buf, gsessdata->basichash.size); /* OK we have a valid token */ mc->established = true; done: ASN_STRUCT_FREE(asn_DEF_GSSSessionData, gsessdata); } void mag_attempt_session(struct mag_req_cfg *cfg, struct mag_conn *mc) { request_rec *req = cfg->req; session_rec *sess = NULL; struct databuf plainbuf = { 0 }; struct databuf cipherbuf = { 0 }; struct databuf ctxbuf = { 0 }; GSSSessionData_t gsessdata = { 0 }; apr_status_t rc; bool ret; /* we save the session only if the authentication is established */ if (!mc->established) return; rc = mag_session_load(req, &sess); if (rc != OK || sess == NULL) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req, "Sessions not available, can't send cookies!"); return; } if (!cfg->mag_skey) { ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req, "Session key not available, aborting."); return; } 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; if (OCTET_STRING_fromString(&gsessdata.gssname, mc->gss_name) != 0) goto done; if (OCTET_STRING_fromBuf(&gsessdata.basichash, (const char *)mc->basic_hash.value, mc->basic_hash.length) != 0) goto done; ret = encode_GSSSessionData(req->pool, &gsessdata, &plainbuf.value, &plainbuf.length); if (ret == false) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "Failed to pack session data!"); goto done; } rc = SEAL_BUFFER(req->pool, cfg->mag_skey, &plainbuf, &cipherbuf); if (rc != OK) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "Failed to seal session data!"); goto done; } ctxbuf.length = apr_base64_encode_len(cipherbuf.length); ctxbuf.value = apr_pcalloc(req->pool, ctxbuf.length); if (!ctxbuf.value) goto done; ctxbuf.length = apr_base64_encode((char *)ctxbuf.value, (char *)cipherbuf.value, cipherbuf.length); rc = mag_session_set(req, sess, MAG_BEARER_KEY, (char *)ctxbuf.value); if (rc != OK) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "Failed to set session data!"); } done: ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GSSSessionData, &gsessdata); } static int mag_basic_hmac(struct seal_key *key, unsigned char *mac, gss_buffer_desc user, gss_buffer_desc pwd) { struct databuf hmacbuf = { mac, 0 }; int data_size = user.length + pwd.length + 1; unsigned char data[data_size]; struct databuf databuf = { data, data_size }; memcpy(data, user.value, user.length); data[user.length] = '\0'; memcpy(&data[user.length + 1], pwd.value, pwd.length); return HMAC_BUFFER(key, &databuf, &hmacbuf); } static int mag_get_mac_size(struct mag_req_cfg *cfg) { if (!cfg->mag_skey) { ap_log_perror(APLOG_MARK, APLOG_INFO, 0, cfg->cfg->pool, "Session key not available, aborting!"); return 0; } return get_mac_size(cfg->mag_skey); } bool mag_basic_check(struct mag_req_cfg *cfg, struct mag_conn *mc, gss_buffer_desc user, gss_buffer_desc pwd) { int mac_size = mag_get_mac_size(cfg); unsigned char mac[mac_size]; int ret, i, j; bool res = false; if (mac_size == 0) return false; if (mc->basic_hash.value == NULL) return false; ret = mag_basic_hmac(cfg->mag_skey, mac, user, pwd); if (ret != 0) goto done; for (i = 0, j = 0; i < mac_size; i++) { if (mc->basic_hash.value[i] != mac[i]) j++; } if (j == 0) res = true; done: if (res == false) { mc->basic_hash.value = NULL; mc->basic_hash.length = 0; } return res; } void mag_basic_cache(struct mag_req_cfg *cfg, struct mag_conn *mc, gss_buffer_desc user, gss_buffer_desc pwd) { int mac_size = mag_get_mac_size(cfg); unsigned char mac[mac_size]; int ret; ret = mag_basic_hmac(cfg->mag_skey, mac, user, pwd); if (ret != 0) return; mc->basic_hash.length = mac_size; mc->basic_hash.value = apr_palloc(mc->pool, mac_size); memcpy(mc->basic_hash.value, mac, mac_size); } mod_auth_gssapi-1.3.2/src/sessions.h000066400000000000000000000010611266122234600174730ustar00rootroot00000000000000/* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */ struct mag_req_cfg; struct mag_conn; void mag_post_config_session(void); void mag_check_session(struct mag_req_cfg *cfg, struct mag_conn **conn); void mag_attempt_session(struct mag_req_cfg *cfg, struct mag_conn *mc); bool mag_basic_check(struct mag_req_cfg *cfg, struct mag_conn *mc, gss_buffer_desc user, gss_buffer_desc pwd); void mag_basic_cache(struct mag_req_cfg *cfg, struct mag_conn *mc, gss_buffer_desc user, gss_buffer_desc pwd); mod_auth_gssapi-1.3.2/tests/000077500000000000000000000000001266122234600160315ustar00rootroot00000000000000mod_auth_gssapi-1.3.2/tests/httpd.conf000066400000000000000000000140411266122234600200230ustar00rootroot00000000000000ServerRoot "${HTTPROOT}" ServerName "${HTTPNAME}" Listen ${HTTPADDR}:${HTTPPORT} Listen ${HTTPADDR}:${PROXYPORT} LoadModule access_compat_module modules/mod_access_compat.so LoadModule actions_module modules/mod_actions.so LoadModule alias_module modules/mod_alias.so LoadModule allowmethods_module modules/mod_allowmethods.so LoadModule auth_basic_module modules/mod_auth_basic.so #LoadModule auth_digest_module modules/mod_auth_digest.so LoadModule authn_anon_module modules/mod_authn_anon.so LoadModule authn_core_module modules/mod_authn_core.so LoadModule authn_dbd_module modules/mod_authn_dbd.so LoadModule authn_dbm_module modules/mod_authn_dbm.so LoadModule authn_file_module modules/mod_authn_file.so LoadModule authn_socache_module modules/mod_authn_socache.so LoadModule authz_core_module modules/mod_authz_core.so LoadModule authz_dbd_module modules/mod_authz_dbd.so LoadModule authz_dbm_module modules/mod_authz_dbm.so LoadModule authz_groupfile_module modules/mod_authz_groupfile.so LoadModule authz_host_module modules/mod_authz_host.so LoadModule authz_owner_module modules/mod_authz_owner.so LoadModule authz_user_module modules/mod_authz_user.so LoadModule autoindex_module modules/mod_autoindex.so LoadModule cache_module modules/mod_cache.so LoadModule cache_disk_module modules/mod_cache_disk.so LoadModule data_module modules/mod_data.so LoadModule dbd_module modules/mod_dbd.so LoadModule deflate_module modules/mod_deflate.so LoadModule dir_module modules/mod_dir.so LoadModule dumpio_module modules/mod_dumpio.so LoadModule echo_module modules/mod_echo.so LoadModule env_module modules/mod_env.so LoadModule expires_module modules/mod_expires.so LoadModule ext_filter_module modules/mod_ext_filter.so LoadModule filter_module modules/mod_filter.so LoadModule headers_module modules/mod_headers.so LoadModule include_module modules/mod_include.so LoadModule info_module modules/mod_info.so LoadModule log_config_module modules/mod_log_config.so LoadModule logio_module modules/mod_logio.so LoadModule macro_module modules/mod_macro.so LoadModule mime_magic_module modules/mod_mime_magic.so LoadModule mime_module modules/mod_mime.so LoadModule negotiation_module modules/mod_negotiation.so LoadModule remoteip_module modules/mod_remoteip.so LoadModule reqtimeout_module modules/mod_reqtimeout.so LoadModule rewrite_module modules/mod_rewrite.so LoadModule session_module modules/mod_session.so LoadModule session_cookie_module modules/mod_session_cookie.so LoadModule setenvif_module modules/mod_setenvif.so LoadModule slotmem_plain_module modules/mod_slotmem_plain.so LoadModule slotmem_shm_module modules/mod_slotmem_shm.so LoadModule socache_dbm_module modules/mod_socache_dbm.so LoadModule socache_memcache_module modules/mod_socache_memcache.so LoadModule socache_shmcb_module modules/mod_socache_shmcb.so LoadModule status_module modules/mod_status.so LoadModule substitute_module modules/mod_substitute.so LoadModule suexec_module modules/mod_suexec.so LoadModule unique_id_module modules/mod_unique_id.so LoadModule unixd_module modules/mod_unixd.so LoadModule userdir_module modules/mod_userdir.so LoadModule version_module modules/mod_version.so LoadModule vhost_alias_module modules/mod_vhost_alias.so LoadModule mpm_prefork_module modules/mod_mpm_prefork.so LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule auth_gssapi_module mod_auth_gssapi.so Options +Includes AddOutputFilter INCLUDES .html AllowOverride none Require all denied DocumentRoot "${HTTPROOT}/html" AllowOverride None # Allow open access: Require all granted Options Indexes FollowSymLinks AllowOverride None Require all granted DirectoryIndex index.html Require all denied PidFile "${HTTPROOT}/logs/httpd.pid" LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined CustomLog "logs/access_log" combined ErrorLog "logs/error_log" LogLevel debug TypesConfig /etc/mime.types AddType application/x-compress .Z AddType application/x-gzip .gz .tgz AddType text/html .shtml AddOutputFilter INCLUDES .shtml AddDefaultCharset UTF-8 IncludeOptional conf.d/*.conf CoreDumpDirectory /tmp AuthType GSSAPI AuthName "Login" GssapiSSLonly Off GssapiUseSessions On Session On SessionCookieName gssapi_session path=/spnego;httponly GssapiCredStore ccache:${HTTPROOT}/tmp/httpd_krb5_ccache GssapiCredStore client_keytab:${HTTPROOT}/http.keytab GssapiCredStore keytab:${HTTPROOT}/http.keytab GssapiBasicAuth Off GssapiAllowedMech krb5 Require valid-user AuthType GSSAPI AuthName "Login Negotiate Once" GssapiSSLonly Off GssapiUseSessions On Session On SessionCookieName gssapi_session path=/spnego_negotiate_once;httponly GssapiCredStore ccache:${HTTPROOT}/tmp/httpd_krb5_ccache GssapiCredStore client_keytab:${HTTPROOT}/http.keytab GssapiCredStore keytab:${HTTPROOT}/http.keytab GssapiBasicAuth Off GssapiAllowedMech krb5 GssapiNegotiateOnce On Require valid-user Options +Includes AddOutputFilter INCLUDES .html AuthType GSSAPI AuthName "Password Login" GssapiSSLonly Off GssapiCredStore ccache:${HTTPROOT}/tmp/httpd_krb5_ccache GssapiCredStore client_keytab:${HTTPROOT}/http.keytab GssapiCredStore keytab:${HTTPROOT}/http.keytab GssapiBasicAuth On GssapiBasicAuthMech krb5 GssapiConnectionBound On Require valid-user ProxyRequests On ProxyVia On AuthType GSSAPI AuthName "Proxy Login" GssapiCredStore ccache:${HTTPROOT}/tmp/httpd_krb5_ccache GssapiCredStore client_keytab:${HTTPROOT}/http.keytab GssapiCredStore keytab:${HTTPROOT}/http.keytab GssapiBasicAuth On Require valid-user mod_auth_gssapi-1.3.2/tests/index.html000066400000000000000000000000351266122234600200240ustar00rootroot00000000000000 mod_auth_gssapi-1.3.2/tests/magtests.py000077500000000000000000000316141266122234600202420ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import argparse import glob import os import random import shutil import signal from string import Template import subprocess import sys import time def parse_args(): parser = argparse.ArgumentParser(description='Mod Auth GSSAPI Tests Environment') parser.add_argument('--path', default='%s/scratchdir' % os.getcwd(), help="Directory in which tests are run") return vars(parser.parse_args()) WRAP_HOSTNAME = "kdc.mag.dev" WRAP_IPADDR = '127.0.0.9' WRAP_HTTP_PORT = '80' WRAP_PROXY_PORT = '8080' def setup_wrappers(base): pkgcfg = subprocess.Popen(['pkg-config', '--exists', 'socket_wrapper']) pkgcfg.wait() if pkgcfg.returncode != 0: raise ValueError('Socket Wrappers not available') pkgcfg = subprocess.Popen(['pkg-config', '--exists', 'nss_wrapper']) pkgcfg.wait() if pkgcfg.returncode != 0: raise ValueError('Socket Wrappers not available') wrapdir = os.path.join(base, 'wrapdir') if not os.path.exists(wrapdir): os.makedirs(wrapdir) hosts_file = os.path.join(testdir, 'hosts') with open(hosts_file, 'w+') as f: f.write('%s %s' % (WRAP_IPADDR, WRAP_HOSTNAME)) wenv = {'LD_PRELOAD': 'libsocket_wrapper.so libnss_wrapper.so', 'SOCKET_WRAPPER_DIR': wrapdir, 'SOCKET_WRAPPER_DEFAULT_IFACE': '9', 'WRAP_PROXY_PORT': WRAP_PROXY_PORT, 'NSS_WRAPPER_HOSTNAME': WRAP_HOSTNAME, 'NSS_WRAPPER_HOSTS': hosts_file} return wenv TESTREALM = "MAG.DEV" KDC_DBNAME = 'db.file' KDC_STASH = 'stash.file' KDC_PASSWORD = 'modauthgssapi' KRB5_CONF_TEMPLATE = ''' [libdefaults] default_realm = ${TESTREALM} dns_lookup_realm = false dns_lookup_kdc = false rdns = false ticket_lifetime = 24h forwardable = yes default_ccache_name = FILE://${TESTDIR}/ccaches/krb5_ccache_XXXXXX [realms] ${TESTREALM} = { kdc =${WRAP_HOSTNAME} } [domain_realm] .mag.dev = ${TESTREALM} mag.dev = ${TESTREALM} [dbmodules] ${TESTREALM} = { database_name = ${KDCDIR}/${KDC_DBNAME} } ''' KDC_CONF_TEMPLATE = ''' [kdcdefaults] kdc_ports = 88 kdc_tcp_ports = 88 restrict_anonymous_to_tgt = true [realms] ${TESTREALM} = { master_key_type = aes256-cts max_life = 7d max_renewable_life = 14d acl_file = ${KDCDIR}/kadm5.acl dict_file = /usr/share/dict/words default_principal_flags = +preauth admin_keytab = ${TESTREALM}/kadm5.keytab key_stash_file = ${KDCDIR}/${KDC_STASH} } [logging] kdc = FILE:${KDCLOG} ''' def setup_kdc(testdir, wrapenv): # setup kerberos environment testlog = os.path.join(testdir, 'kerb.log') krb5conf = os.path.join(testdir, 'krb5.conf') kdcconf = os.path.join(testdir, 'kdc.conf') kdcdir = os.path.join(testdir, 'kdc') kdcstash = os.path.join(kdcdir, KDC_STASH) kdcdb = os.path.join(kdcdir, KDC_DBNAME) if os.path.exists(kdcdir): shutil.rmtree(kdcdir) os.makedirs(kdcdir) t = Template(KRB5_CONF_TEMPLATE) text = t.substitute({'TESTREALM': TESTREALM, 'TESTDIR': testdir, 'KDCDIR': kdcdir, 'KDC_DBNAME': KDC_DBNAME, 'WRAP_HOSTNAME': WRAP_HOSTNAME}) with open(krb5conf, 'w+') as f: f.write(text) t = Template(KDC_CONF_TEMPLATE) text = t.substitute({'TESTREALM': TESTREALM, 'KDCDIR': kdcdir, 'KDCLOG': testlog, 'KDC_STASH': KDC_STASH}) with open(kdcconf, 'w+') as f: f.write(text) kdcenv = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin', 'KRB5_CONFIG': krb5conf, 'KRB5_KDC_PROFILE': kdcconf, 'KRB5_TRACE': os.path.join(testdir, 'krbtrace.log')} kdcenv.update(wrapenv) with (open(testlog, 'a')) as logfile: ksetup = subprocess.Popen(["kdb5_util", "create", "-s", "-r", TESTREALM, "-P", KDC_PASSWORD], stdout=logfile, stderr=logfile, env=kdcenv, preexec_fn=os.setsid) ksetup.wait() if ksetup.returncode != 0: raise ValueError('KDC Setup failed') with (open(testlog, 'a')) as logfile: kdcproc = subprocess.Popen(['krb5kdc', '-n'], stdout=logfile, stderr=logfile, env=kdcenv, preexec_fn=os.setsid) return kdcproc, kdcenv def kadmin_local(cmd, env, logfile): ksetup = subprocess.Popen(["kadmin.local", "-q", cmd], stdout=logfile, stderr=logfile, env=env, preexec_fn=os.setsid) ksetup.wait() if ksetup.returncode != 0: raise ValueError('Kadmin local [%s] failed' % cmd) USR_NAME = "maguser" USR_PWD = "magpwd" USR_NAME_2 = "maguser2" USR_PWD_2 = "magpwd2" SVC_KTNAME = "httpd/http.keytab" KEY_TYPE = "aes256-cts-hmac-sha1-96:normal" def setup_keys(tesdir, env): testlog = os.path.join(testdir, 'kerb.log') svc_name = "HTTP/%s" % WRAP_HOSTNAME svc_keytab = os.path.join(testdir, SVC_KTNAME) cmd = "addprinc -randkey -e %s %s" % (KEY_TYPE, svc_name) with (open(testlog, 'a')) as logfile: kadmin_local(cmd, env, logfile) cmd = "ktadd -k %s -e %s %s" % (svc_keytab, KEY_TYPE, svc_name) with (open(testlog, 'a')) as logfile: kadmin_local(cmd, env, logfile) cmd = "addprinc -pw %s -e %s %s" % (USR_PWD, KEY_TYPE, USR_NAME) with (open(testlog, 'a')) as logfile: kadmin_local(cmd, env, logfile) cmd = "addprinc -pw %s -e %s %s" % (USR_PWD_2, KEY_TYPE, USR_NAME_2) with (open(testlog, 'a')) as logfile: kadmin_local(cmd, env, logfile) keys_env = { "KRB5_KTNAME": svc_keytab } keys_env.update(env) return keys_env def setup_http(testdir, wrapenv): httpdir = os.path.join(testdir, 'httpd') if os.path.exists(httpdir): shutil.rmtree(httpdir) os.makedirs(httpdir) os.mkdir(os.path.join(httpdir, 'conf.d')) os.mkdir(os.path.join(httpdir, 'html')) os.mkdir(os.path.join(httpdir, 'logs')) os.symlink('/etc/httpd/modules', os.path.join(httpdir, 'modules')) shutil.copy('src/.libs/mod_auth_gssapi.so', httpdir) with open('tests/httpd.conf') as f: t = Template(f.read()) text = t.substitute({'HTTPROOT': httpdir, 'HTTPNAME': WRAP_HOSTNAME, 'HTTPADDR': WRAP_IPADDR, 'PROXYPORT': WRAP_PROXY_PORT, 'HTTPPORT': WRAP_HTTP_PORT}) config = os.path.join(httpdir, 'httpd.conf') with open(config, 'w+') as f: f.write(text) httpenv = {'PATH': '/sbin:/bin:/usr/sbin:/usr/bin', 'MALLOC_CHECK_': '3', 'MALLOC_PERTURB_': str(random.randint(0, 32767) % 255 + 1)} httpenv.update(wrapenv) httpproc = subprocess.Popen(['httpd', '-DFOREGROUND', '-f', config], env=httpenv, preexec_fn=os.setsid) return httpproc def kinit_user(testdir, kdcenv): testlog = os.path.join(testdir, 'kinit.log') ccache = os.path.join(testdir, 'k5ccache') testenv = {'KRB5CCNAME': ccache} testenv.update(kdcenv) with (open(testlog, 'a')) as logfile: kinit = subprocess.Popen(["kinit", USR_NAME], stdin=subprocess.PIPE, stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) kinit.communicate('%s\n' % USR_PWD) kinit.wait() if kinit.returncode != 0: raise ValueError('kinit failed') return testenv def test_spnego_auth(testdir, testenv, testlog): spnegodir = os.path.join(testdir, 'httpd', 'html', 'spnego') os.mkdir(spnegodir) shutil.copy('tests/index.html', spnegodir) with (open(testlog, 'a')) as logfile: spnego = subprocess.Popen(["tests/t_spnego.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) spnego.wait() if spnego.returncode != 0: sys.stderr.write('SPNEGO: FAILED\n') else: sys.stderr.write('SPNEGO: SUCCESS\n') with (open(testlog, 'a')) as logfile: spnego = subprocess.Popen(["tests/t_spnego_proxy.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) spnego.wait() if spnego.returncode != 0: sys.stderr.write('SPNEGO Proxy Auth: FAILED\n') else: sys.stderr.write('SPNEGO Proxy Auth: SUCCESS\n') with (open(testlog, 'a')) as logfile: spnego = subprocess.Popen(["tests/t_spnego_no_auth.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) spnego.wait() if spnego.returncode != 0: sys.stderr.write('SPNEGO No Auth: FAILED\n') else: sys.stderr.write('SPNEGO No Auth: SUCCESS\n') def test_spnego_negotiate_once(testdir, testenv, testlog): spnego_negotiate_once_dir = os.path.join(testdir, 'httpd', 'html', 'spnego_negotiate_once') os.mkdir(spnego_negotiate_once_dir) shutil.copy('tests/index.html', spnego_negotiate_once_dir) with (open(testlog, 'a')) as logfile: spnego = subprocess.Popen(["tests/t_spnego_negotiate_once.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) spnego.wait() if spnego.returncode != 0: sys.stderr.write('SPNEGO Negotiate Once: FAILED\n') else: sys.stderr.write('SPNEGO Negotiate Once: SUCCESS\n') def test_basic_auth_krb5(testdir, testenv, testlog): basicdir = os.path.join(testdir, 'httpd', 'html', 'basic_auth_krb5') os.mkdir(basicdir) shutil.copy('tests/index.html', basicdir) with (open(testlog, 'a')) as logfile: basick5 = subprocess.Popen(["tests/t_basic_k5.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) basick5.wait() if basick5.returncode != 0: sys.stderr.write('BASIC-AUTH: FAILED\n') else: sys.stderr.write('BASIC-AUTH: SUCCESS\n') with (open(testlog, 'a')) as logfile: basick5 = subprocess.Popen(["tests/t_basic_k5_two_users.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) basick5.wait() if basick5.returncode != 0: sys.stderr.write('BASIC-AUTH Two Users: FAILED\n') else: sys.stderr.write('BASIC-AUTH Two Users: SUCCESS\n') with (open(testlog, 'a')) as logfile: basick5 = subprocess.Popen(["tests/t_basic_k5_fail_second.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) basick5.wait() if basick5.returncode != 0: sys.stderr.write('BASIC Fail Second User: FAILED\n') else: sys.stderr.write('BASIC Fail Second User: SUCCESS\n') with (open(testlog, 'a')) as logfile: basick5 = subprocess.Popen(["tests/t_basic_proxy.py"], stdout=logfile, stderr=logfile, env=testenv, preexec_fn=os.setsid) basick5.wait() if basick5.returncode != 0: sys.stderr.write('BASIC Proxy Auth: FAILED\n') else: sys.stderr.write('BASIC Proxy Auth: SUCCESS\n') if __name__ == '__main__': args = parse_args() testdir = args['path'] if os.path.exists(testdir): shutil.rmtree(testdir) os.makedirs(testdir) processes = dict() testlog = os.path.join(testdir, 'tests.log') try: wrapenv = setup_wrappers(testdir) kdcproc, kdcenv = setup_kdc(testdir, wrapenv) processes['KDC(%d)' % kdcproc.pid] = kdcproc httpproc = setup_http(testdir, kdcenv) processes['HTTPD(%d)' % httpproc.pid] = httpproc keysenv = setup_keys(testdir, kdcenv) testenv = kinit_user(testdir, kdcenv) test_spnego_auth(testdir, testenv, testlog) test_spnego_negotiate_once(testdir, testenv, testlog) testenv = {'MAG_USER_NAME': USR_NAME, 'MAG_USER_PASSWORD': USR_PWD, 'MAG_USER_NAME_2': USR_NAME_2, 'MAG_USER_PASSWORD_2': USR_PWD_2} testenv.update(kdcenv) test_basic_auth_krb5(testdir, testenv, testlog) finally: with (open(testlog, 'a')) as logfile: for name in processes: logfile.write("Killing %s\n" % name) os.killpg(processes[name].pid, signal.SIGTERM) mod_auth_gssapi-1.3.2/tests/t_basic_k5.py000077500000000000000000000007601266122234600204140ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests from requests.auth import HTTPBasicAuth if __name__ == '__main__': url = 'http://%s/basic_auth_krb5/' % os.environ['NSS_WRAPPER_HOSTNAME'] r = requests.get(url, auth=HTTPBasicAuth(os.environ['MAG_USER_NAME'], os.environ['MAG_USER_PASSWORD'])) if r.status_code != 200: raise ValueError('Basic Auth Failed') mod_auth_gssapi-1.3.2/tests/t_basic_k5_fail_second.py000077500000000000000000000027271266122234600227470ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests from requests.auth import HTTPBasicAuth if __name__ == '__main__': s = requests.Session() url = 'http://%s:%s@%s/basic_auth_krb5/' % (os.environ['MAG_USER_NAME'], os.environ['MAG_USER_PASSWORD'], os.environ['NSS_WRAPPER_HOSTNAME']) r = s.get(url) if r.status_code != 200: raise ValueError('Basic Auth: Failed Authentication') url = 'http://%s:%s@%s/basic_auth_krb5/' % (os.environ['MAG_USER_NAME_2'], os.environ['MAG_USER_PASSWORD'], os.environ['NSS_WRAPPER_HOSTNAME']) r = s.get(url) if r.status_code == 200: raise ValueError('Basic Auth: Got Success while expecting Error') url = 'http://%s:%s@%s/basic_auth_krb5/' % (os.environ['MAG_USER_NAME_2'], os.environ['MAG_USER_PASSWORD_2'], os.environ['NSS_WRAPPER_HOSTNAME']) r = s.get(url) if r.status_code != 200: raise ValueError('Basic Auth: Failed Authentication') url = 'http://%s/basic_auth_krb5/' % os.environ['NSS_WRAPPER_HOSTNAME'] r = s.get(url) if r.status_code == 200: raise ValueError('Basic Auth: Got Success while expecting Error') mod_auth_gssapi-1.3.2/tests/t_basic_k5_two_users.py000077500000000000000000000017221266122234600225250ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests from requests.auth import HTTPBasicAuth if __name__ == '__main__': s = requests.Session() url = 'http://%s:%s@%s/basic_auth_krb5/' % (os.environ['MAG_USER_NAME'], os.environ['MAG_USER_PASSWORD'], os.environ['NSS_WRAPPER_HOSTNAME']) r = s.get(url) if r.status_code != 200: raise ValueError('Basic Auth Failed') url = 'http://%s:%s@%s/basic_auth_krb5/' % (os.environ['MAG_USER_NAME_2'], os.environ['MAG_USER_PASSWORD_2'], os.environ['NSS_WRAPPER_HOSTNAME']) r2 = s.get(url) if r2.status_code != 200: raise ValueError('Basic Auth failed') if r.text == r2.text: raise ValueError('Basic Auth fatal error') mod_auth_gssapi-1.3.2/tests/t_basic_proxy.py000077500000000000000000000015231266122234600212540ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests from requests.auth import HTTPBasicAuth if __name__ == '__main__': proxy = 'http://%s:%s@%s:%s' % (os.environ['MAG_USER_NAME'], os.environ['MAG_USER_PASSWORD'], os.environ['NSS_WRAPPER_HOSTNAME'], os.environ['WRAP_PROXY_PORT']) proxies = { "http": proxy, } url = 'http://%s/basic_auth_krb5/' % os.environ['NSS_WRAPPER_HOSTNAME'] r = requests.get(url, proxies=proxies, auth=HTTPBasicAuth(os.environ['MAG_USER_NAME_2'], os.environ['MAG_USER_PASSWORD_2'])) if r.status_code != 200: raise ValueError('Basic Proxy Auth Failed') mod_auth_gssapi-1.3.2/tests/t_spnego.py000077500000000000000000000006501266122234600202250ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests from requests_kerberos import HTTPKerberosAuth, OPTIONAL if __name__ == '__main__': sess = requests.Session() url = 'http://%s/spnego/' % os.environ['NSS_WRAPPER_HOSTNAME'] r = sess.get(url, auth=HTTPKerberosAuth()) if r.status_code != 200: raise ValueError('Spnego failed') mod_auth_gssapi-1.3.2/tests/t_spnego_negotiate_once.py000077500000000000000000000027131266122234600232720ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests from requests_kerberos import HTTPKerberosAuth, OPTIONAL if __name__ == '__main__': sess = requests.Session() url = 'http://%s/spnego_negotiate_once/' % ( os.environ['NSS_WRAPPER_HOSTNAME']) # ensure a 401 with the appropriate WWW-Authenticate header is returned # when no auth is provided r = sess.get(url) if r.status_code != 401: raise ValueError('Spnego Negotiate Once failed - 401 expected') if not (r.headers.get("WWW-Authenticate") and r.headers.get("WWW-Authenticate").startswith("Negotiate")): raise ValueError('Spnego Negotiate Once failed - WWW-Authenticate ' 'Negotiate header missing') # test sending a bad Authorization header with GssapiNegotiateOnce enabled r = sess.get(url, headers={"Authorization": "Negotiate badvalue"}) if r.status_code != 401: raise ValueError('Spnego Negotiate Once failed - 401 expected') if r.headers.get("WWW-Authenticate"): raise ValueError('Spnego Negotiate Once failed - WWW-Authenticate ' 'Negotiate present but GssapiNegotiateOnce is ' 'enabled') # ensure a 200 is returned when valid auth is provided r = sess.get(url, auth=HTTPKerberosAuth()) if r.status_code != 200: raise ValueError('Spnego Negotiate Once failed') mod_auth_gssapi-1.3.2/tests/t_spnego_no_auth.py000077500000000000000000000012151266122234600217400ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests from requests_kerberos import HTTPKerberosAuth, OPTIONAL if __name__ == '__main__': sess = requests.Session() url = 'http://%s/spnego/' % os.environ['NSS_WRAPPER_HOSTNAME'] r = sess.get(url) if r.status_code != 401: raise ValueError('Spnego failed - 401 expected') if not (r.headers.get("WWW-Authenticate") and r.headers.get("WWW-Authenticate").startswith("Negotiate")): raise ValueError('Spnego failed - WWW-Authenticate Negotiate header ' 'missing') mod_auth_gssapi-1.3.2/tests/t_spnego_proxy.py000077500000000000000000000017341266122234600214720ustar00rootroot00000000000000#!/usr/bin/python # Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license. import os import requests import gssapi from base64 import b64encode def getAuthToken(target): spnego_mech = gssapi.raw.OID.from_int_seq('1.3.6.1.5.5.2') name = gssapi.Name('HTTP@%s' % target, gssapi.NameType.hostbased_service) ctx = gssapi.SecurityContext(name=name, mech=spnego_mech) token = ctx.step() return 'Negotiate %s' % b64encode(token) if __name__ == '__main__': s = requests.Session() target = os.environ['NSS_WRAPPER_HOSTNAME'] url = 'http://%s/spnego/' % target proxy = 'http://%s:%s' % (target, os.environ['WRAP_PROXY_PORT']) proxies = { "http" : proxy, } s.headers.update({'Proxy-Authorization': getAuthToken(target)}) s.headers.update({'Authorization': getAuthToken(target)}) r = s.get(url, proxies=proxies) if r.status_code != 200: raise ValueError('Spnego Proxy Auth Failed')