/*XXX: Needs length to be returned, signatures are binary blobs */
static char *base64url_decode(apr_pool_t * p, const char *input)
{
  int len = apr_base64_decode_len(input);
  char *decoded = apr_pcalloc(p, len);
  len = apr_base64_decode(decoded, input);
  return decoded;
}
Exemple #2
0
/*
 * base64url decode a string
 */
int apr_jwt_base64url_decode(apr_pool_t *pool, char **dst, const char *src,
		int padding) {
	if (src == NULL)
		return -1;
	char *dec = apr_pstrdup(pool, src);
	int i = 0;
	while (dec[i] != '\0') {
		if (dec[i] == '-')
			dec[i] = '+';
		if (dec[i] == '_')
			dec[i] = '/';
		if (dec[i] == ',')
			dec[i] = '=';
		i++;
	}
	if (padding == 1) {
		switch (strlen(dec) % 4) {
		case 0:
			break;
		case 2:
			dec = apr_pstrcat(pool, dec, "==", NULL);
			break;
		case 3:
			dec = apr_pstrcat(pool, dec, "=", NULL);
			break;
		default:
			return 0;
		}
	}
	int dlen = apr_base64_decode_len(dec);
	*dst = apr_palloc(pool, dlen);
	return apr_base64_decode(*dst, dec);
}
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;
}
/* Read the header sent by the server (if any), invoke the gssapi authn
   code and use the resulting Server Ticket  on the next request to the
   server. */
static apr_status_t
do_auth(int code,
        gss_authn_info_t *gss_info,
        serf_connection_t *conn,
        const char *auth_hdr,
        apr_pool_t *pool)
{
    serf_context_t *ctx = conn->ctx;
    serf__authn_info_t *authn_info = (code == 401) ? &ctx->authn_info :
        &ctx->proxy_authn_info;
    const char *tmp = NULL;
    char *token = NULL;
    apr_size_t tmp_len = 0, token_len = 0;
    const char *space = NULL;
    apr_status_t status;

    /* The server will return a token as attribute to the Negotiate key.
       Negotiate YGwGCSqGSIb3EgECAgIAb10wW6ADAgEFoQMCAQ+iTzBNoAMCARCiRgREa6mouM
       BAMFqKVdTGtfpZNXKzyw4Yo1paphJdIA3VOgncaoIlXxZLnkHiIHS2v65pVvrp
       bRIyjF8xve9HxpnNIucCY9c=

       Read this base64 value, decode it and validate it so we're sure the server
       is who we expect it to be. */
    if (auth_hdr)
        space = strchr(auth_hdr, ' ');

    if (space) {
        token = apr_palloc(pool, apr_base64_decode_len(space + 1));
        token_len = apr_base64_decode(token, space + 1);
    }

    /* We can get a whole batch of 401 responses from the server, but we should
       only start the authentication phase once, so if we started authentication
       already ignore all responses with initial Negotiate authentication header.

       Note: as we set the max. transfer rate to one message at a time until the
       authentication cycle is finished, this check shouldn't be needed. */
    if (!token && gss_info->state != gss_api_auth_not_started)
        return APR_SUCCESS;

    status = gss_api_get_credentials(token, token_len, conn->host_info.hostname,
                                     &tmp, &tmp_len,
                                     gss_info);
    if (status)
        return status;

    serf__encode_auth_header(&gss_info->value, authn_info->scheme->name,
                             tmp,
                             tmp_len,
                             pool);
    gss_info->header = (code == 401) ? "Authorization" : "Proxy-Authorization";

    /* If the handshake is finished tell serf it can send as much requests as it
       likes. */
    if (gss_info->state == gss_api_auth_completed)
        serf_connection_set_max_outstanding_requests(conn, 0);

    return APR_SUCCESS;
}
Exemple #5
0
/*
 * parse a base64 encoded binary value from the provided string
 */
static char *oidc_parse_base64(apr_pool_t *pool, const char *input,
		char **output, int *output_len) {
	int len = apr_base64_decode_len(input);
	*output = apr_palloc(pool, len);
	*output_len = apr_base64_decode(*output, input);
	if (*output_len <= 0)
		return apr_psprintf(pool, "base64-decoding of \"%s\" failed", input);
	return NULL;
}
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
std::vector<U8> LLBase64::decode(std::string input)
{
	std::vector<U8> data;
	if (input.length() > 0)
	{
		// Because we're decoding binary data, we don't want the null terminator
		// figured into our array size calculations, so we reduce the reported size by 1.
		size_t data_length = static_cast<size_t>(apr_base64_decode_len(input.c_str())) - 1;
		if (data_length > 0)
		{
			data.resize(data_length);
			apr_base64_decode_binary(&data[0], input.c_str());
		}
	}
	
	return data;
}
Exemple #8
0
/* Helper to create CryptoAPI CERT_CONTEXT from base64 encoded BASE64_CERT.
 * Returns NULL on error.
 */
static PCCERT_CONTEXT
certcontext_from_base64(const char *base64_cert, apr_pool_t *pool)
{
  PCCERT_CONTEXT cert_context = NULL;
  int cert_len;
  BYTE *binary_cert;

  /* Use apr-util as CryptStringToBinaryA is available only on XP+. */
  binary_cert = apr_palloc(pool,
                           apr_base64_decode_len(base64_cert));
  cert_len = apr_base64_decode((char*)binary_cert, base64_cert);

  /* Parse the certificate into a context. */
  cert_context = CertCreateCertificateContext
    (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, binary_cert, cert_len);

  return cert_context;
}
static int get_basic_auth(request_rec *r, const char **user,
                          const char **pw)
{
    const char *auth_line;
    char *decoded_line;
    int length;

    /* Get the appropriate header */
    auth_line = apr_table_get(r->headers_in, (PROXYREQ_PROXY == r->proxyreq)
                                              ? "Proxy-Authorization"
                                              : "Authorization");

    if (!auth_line) {
        note_basic_auth_failure(r);
        return HTTP_UNAUTHORIZED;
    }

    if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
        /* Client tried to authenticate using wrong auth scheme */
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01614)
                      "client used wrong authentication scheme: %s", r->uri);
        note_basic_auth_failure(r);
        return HTTP_UNAUTHORIZED;
    }

    /* Skip leading spaces. */
    while (apr_isspace(*auth_line)) {
        auth_line++;
    }

    decoded_line = apr_palloc(r->pool, apr_base64_decode_len(auth_line) + 1);
    length = apr_base64_decode(decoded_line, auth_line);
    /* Null-terminate the string. */
    decoded_line[length] = '\0';

    *user = ap_getword_nulls(r->pool, (const char**)&decoded_line, ':');
    *pw = decoded_line;

    /* set the user, even though the user is unauthenticated at this point */
    r->user = (char *) *user;

    return OK;
}
Exemple #10
0
int lua_apr_base64_decode(lua_State *L)
{
  size_t plain_len, coded_len;
  apr_pool_t *memory_pool;
  const char *coded;
  char *plain;

  memory_pool = to_pool(L);
  coded = luaL_checklstring(L, 1, &coded_len);
  plain_len = apr_base64_decode_len(coded);
  plain = apr_palloc(memory_pool, plain_len);
  if (plain == NULL)
    return push_error_memory(L);
  plain_len = apr_base64_decode(plain, coded);
  if (plain_len > 0 && plain[plain_len - 1] == '\0')
    plain_len--;
  lua_pushlstring(L, plain, plain_len);
  return 1;
}
Exemple #11
0
/* do_auth is invoked in two situations:
   - when a response from a server is received that contains an authn header
     (either from a 40x or 2xx response)
   - when a request is prepared on a connection with stateless authentication.

   Read the header sent by the server (if any), invoke the gssapi authn
   code and use the resulting Server Ticket on the next request to the
   server. */
static apr_status_t
do_auth(peer_t peer,
        int code,
        gss_authn_info_t *gss_info,
        serf_connection_t *conn,
        serf_request_t *request,
        const char *auth_hdr,
        apr_pool_t *pool)
{
    serf_context_t *ctx = conn->ctx;
    serf__authn_info_t *authn_info;
    const char *tmp = NULL;
    char *token = NULL;
    apr_size_t tmp_len = 0, token_len = 0;
    apr_status_t status;

    if (peer == HOST) {
        authn_info = serf__get_authn_info_for_server(conn);
    } else {
        authn_info = &ctx->proxy_authn_info;
    }

    /* Is this a response from a host/proxy? auth_hdr should always be set. */
    if (code && auth_hdr) {
        const char *space = NULL;
        /* The server will return a token as attribute to the Negotiate key.
           Negotiate YGwGCSqGSIb3EgECAgIAb10wW6ADAgEFoQMCAQ+iTzBNoAMCARCiRgREa6
           mouMBAMFqKVdTGtfpZNXKzyw4Yo1paphJdIA3VOgncaoIlXxZLnkHiIHS2v65pVvrp
           bRIyjF8xve9HxpnNIucCY9c=

           Read this base64 value, decode it and validate it so we're sure the
           server is who we expect it to be. */
        space = strchr(auth_hdr, ' ');

        if (space) {
            token = apr_palloc(pool, apr_base64_decode_len(space + 1));
            token_len = apr_base64_decode(token, space + 1);
        }
    } else {
        /* This is a new request, not a retry in response to a 40x of the
           host/proxy. 
           Only add the Authorization header if we know the server requires
           per-request authentication (stateless). */
        if (gss_info->pstate != pstate_stateless)
            return APR_SUCCESS;
    }

    switch(gss_info->pstate) {
        case pstate_init:
            /* Nothing to do here */
            break;
        case pstate_undecided: /* Fall through */
        case pstate_stateful:
            {
                /* Switch to stateless mode, from now on handle authentication
                   of each request with a new gss context. This is easiest to
                   manage when sending requests one by one. */
                serf__log_skt(AUTH_VERBOSE, __FILE__, conn->skt,
                              "Server requires per-request SPNEGO authn, "
                              "switching to stateless mode.\n");

                gss_info->pstate = pstate_stateless;
                serf_connection_set_max_outstanding_requests(conn, 1);
                break;
            }
        case pstate_stateless:
            /* Nothing to do here */
            break;
    }

    if (request->auth_baton && !token) {
        /* We provided token with this request, but server responded with empty
           authentication header. This means server rejected our credentials.
           XXX: Probably we need separate error code for this case like
           SERF_ERROR_AUTHN_CREDS_REJECTED? */
        return SERF_ERROR_AUTHN_FAILED;
    }

    /* If the server didn't provide us with a token, start with a new initial
       step in the SPNEGO authentication. */
    if (!token) {
        serf__spnego_reset_sec_context(gss_info->gss_ctx);
        gss_info->state = gss_api_auth_not_started;
    }

    if (peer == HOST) {
        status = gss_api_get_credentials(conn,
                                         token, token_len,
                                         conn->host_info.hostname,
                                         &tmp, &tmp_len,
                                         gss_info);
    } else {
        char *proxy_host = conn->ctx->proxy_address->hostname;
        status = gss_api_get_credentials(conn,
                                         token, token_len, proxy_host,
                                         &tmp, &tmp_len,
                                         gss_info);
    }
    if (status)
        return status;

    /* On the next request, add an Authorization header. */
    if (tmp_len) {
        serf__encode_auth_header(&gss_info->value, authn_info->scheme->name,
                                 tmp,
                                 tmp_len,
                                 pool);
        gss_info->header = (peer == HOST) ?
            "Authorization" : "Proxy-Authorization";
    }

    return APR_SUCCESS;
}
void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
{
	#ifdef XML_PARSER_PERFORMANCE_TESTS
	XML_Timer timer(&endElementTime);
	#endif // XML_PARSER_PERFORMANCE_TESTS

	--mDepth;
	if (mSkipping)
	{
		if (mDepth < mSkipThrough)
		{
			mSkipping = false;
		}
		return;
	}

	Element element = readElement(name);

	switch (element)
	{
		case ELEMENT_LLSD:
			if (mInLLSDElement)
			{
				mInLLSDElement = false;
				mGracefullStop = true;
				XML_StopParser(mParser, false);
			}
			return;

		case ELEMENT_KEY:
			mCurrentKey = mCurrentContent;
			return;

		default:
			// all rest are values, fall through
			;
	}

	if (!mInLLSDElement) { return; }

	LLSD& value = *mStack.back();
	mStack.pop_back();

	switch (element)
	{
		case ELEMENT_UNDEF:
			value.clear();
			break;

		case ELEMENT_BOOL:
			value = (mCurrentContent == "true" || mCurrentContent == "1");
			break;

		case ELEMENT_INTEGER:
		{
			S32 i;
			if (sscanf(mCurrentContent.c_str(), "%d", &i) == 1)
			{	// See if sscanf works - it's faster
				value = i;
			}
			else
			{
				value = LLSD(mCurrentContent).asInteger();
			}
			break;
		}

		case ELEMENT_REAL:
		{
			// sscanf() is sensitive to the locale and will fail decoding
			// the decimal point for locales where the decimal separator
			// is a comma... So, better not using sscanf() for this purpose.
			// See http://jira.secondlife.com/browse/EXP-700
#if 0
			F64 r;
			if (sscanf(mCurrentContent.c_str(), "%lf", &r) == 1)
			{	// See if sscanf works - it's faster
				value = r;
			}
			else
			{
				value = LLSD(mCurrentContent).asReal();
			}
#else
			value = LLSD(mCurrentContent).asReal();
#endif
			break;
		}

		case ELEMENT_STRING:
			value = mCurrentContent;
			break;

		case ELEMENT_UUID:
			value = LLSD(mCurrentContent).asUUID();
			break;

		case ELEMENT_DATE:
			value = LLSD(mCurrentContent).asDate();
			break;

		case ELEMENT_URI:
			value = LLSD(mCurrentContent).asURI();
			break;

		case ELEMENT_BINARY:
		{
			// Regex is expensive, but only fix for whitespace in base64,
			// created by python and other non-linden systems - DEV-39358
			// Fortunately we have very little binary passing now,
			// so performance impact shold be negligible. + poppy 2009-09-04
			boost::regex r;
			r.assign("\\s");
			std::string stripped = boost::regex_replace(mCurrentContent, r, "");
			S32 len = apr_base64_decode_len(stripped.c_str());
			std::vector<U8> data;
			data.resize(len);
			len = apr_base64_decode_binary(&data[0], stripped.c_str());
			data.resize(len);
			value = data;
			break;
		}

		case ELEMENT_UNKNOWN:
			value.clear();
			break;

		default:
			// other values, map and array, have already been set
			break;
	}

	mCurrentContent.clear();
}
Exemple #13
0
void mag_check_session(request_rec *req,
                       struct mag_config *cfg, struct mag_conn **conn)
{
    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 };
    char *next, *last;
    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) {
        mc = apr_pcalloc(req->pool, sizeof(struct mag_conn));
        if (!mc) return;

        mc->parent = req->pool;
        *conn = mc;
    }

    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;
    }

    /* get time */
    next = apr_strtok((char *)ctxbuf.value, ":", &last);
    expiration = (time_t)apr_atoi64(next);
    if (expiration < time(NULL)) {
        /* credentials fully expired, return nothing */
        return;
    }

    /* user name is next */
    next = apr_strtok(NULL, ":", &last);
    mc->user_name = apr_pstrdup(mc->parent, next);
    if (!mc->user_name) return;

    /* gssapi name (often a principal) is last.
     * (because it may contain the separator as a valid char we
     * just read last as is, without further tokenizing */
    mc->gss_name = apr_pstrdup(mc->parent, last);
    if (!mc->gss_name) return;

    /* OK we have a valid token */
    mc->established = true;
}
static int check_auth_cookie(request_rec *r)
{

	const char *cookies = NULL, *auth_line = NULL;
	char *cookie = NULL;

    /* Debug. */
	/*ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
	    "check_auth_cookie called");*/

	/* Get config for this directory. */
    cookie_auth_config_rec *conf = ap_get_module_config(r->per_dir_config,
		&auth_cookie_module);

    /* Check we have been configured. */
    if (!conf->cookie_auth_cookie) {
        return DECLINED;
    }

	/* Do not override real auth header, unless config instructs us to. */
	if (!conf->cookie_auth_override &&
		apr_table_get(r->headers_in, "Authorization")) {
		if (conf->cookie_auth_env) {
			unsetenv(conf->cookie_auth_env);
		}
		return DECLINED;
	}

	/* todo: protect against xxxCookieNamexxx, regex? */
	/* todo: make case insensitive? */
	/* Get the cookie (code from mod_log_config). */
	if ((cookies = apr_table_get(r->headers_in, "Cookie"))) {
		char *start_cookie, *end_cookie;
		if ((start_cookie = ap_strstr_c(cookies, conf->cookie_auth_cookie))) {
		    start_cookie += strlen(conf->cookie_auth_cookie) + 1;
		    cookie = apr_pstrdup(r->pool, start_cookie);
			/* kill everything in cookie after ';' */
			end_cookie = strchr(cookie, ';');
			if (end_cookie) {
				*end_cookie = '\0';
      }
      ap_unescape_url(cookie);
		}
	}

	/* No cookie? Nothing for us to do. */
	if (!cookie) {
                if (conf->cookie_auth_unauth_redirect) {
        	        const char* redirect = conf->cookie_auth_unauth_redirect;
        		compose_and_set_redirect(r, redirect);
                        return HTTP_MOVED_TEMPORARILY;
                }
                else {
			return DECLINED;
                }
	}

	/* Debug. */
	/*ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
	    "%s=%s", conf->cookie_auth_cookie, cookie);*/

	char* aux_auth_info = "";

	/* Construct the fake auth_line. */
	if (conf->cookie_auth_base64) {
		char* decoded_cookie = apr_palloc(r->pool, apr_base64_decode_len(cookie));
    int decoded_cookie_length = apr_base64_decode(decoded_cookie, cookie);

		int valid = 1;

		/* if the cookie is encrypted, decrypt it in place */
		if (conf->cookie_auth_encrypt) {
      MCRYPT td = mcrypt_module_open("rijndael-128", NULL, "cbc", NULL);
      int keysize = strlen(conf->cookie_auth_encrypt);
      int blocksize = mcrypt_enc_get_block_size(td);

			// We will copy the iv from the beginning of the cookie.
			// The iv does not need to be null-terminated, but we will
			// null-terminate it for convenience.
			int iv_length = mcrypt_enc_get_iv_size(td);
			char* iv = (char*) apr_palloc(r->pool, iv_length + 1);
			memcpy(iv, decoded_cookie, iv_length);
			iv[iv_length] = '\0';

			// Take the iv off the beginning of the cookie
			decoded_cookie += iv_length;
      decoded_cookie_length -= iv_length;

      mcrypt_generic_init( td, conf->cookie_auth_encrypt, keysize, iv);
      // Encryption in CBC is performed in blocks, so our
      // decryption string will always be an integral number
      // of full blocks.
      char* decrypt_ptr = decoded_cookie;
      while (decoded_cookie_length >= blocksize) {
        mdecrypt_generic(td, decrypt_ptr, blocksize);
        decrypt_ptr += blocksize;
        decoded_cookie_length -= blocksize;
      }
      if (decoded_cookie_length != 0) {
        valid = 0;
      }
      mcrypt_generic_deinit (td);
      mcrypt_module_close(td);
      /*ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
        "mdecrypt(%s)=%s", conf->cookie_auth_cookie, decoded_cookie);*/
		}

		/* if the cookie did not decrypt, then do nothing */
		if (valid) {
			char* end_auth_info = strchr(decoded_cookie, '\t');

			if (end_auth_info) {
				aux_auth_info = decoded_cookie;
				char* unencoded_cookie = end_auth_info + 1;
				*end_auth_info = 0;

				auth_line = apr_pstrcat(r->pool, "Basic ", ap_pbase64encode(r->pool, unencoded_cookie), NULL);
			}
			else {
				auth_line = apr_pstrcat(r->pool, "Basic ", ap_pbase64encode(r->pool, decoded_cookie), NULL);
			}
		}
	} else {
		// Aux auth info and cookie encrypt features only available in base64 mode
		ap_unescape_url(cookie);
		auth_line = apr_pstrcat(r->pool, "Basic ",
			ap_pbase64encode(r->pool, cookie), NULL);
	}

	/* If there is aux auth info, then set the env variable */
	if (conf->cookie_auth_env) {
	  apr_table_set(r->subprocess_env, conf->cookie_auth_env, aux_auth_info);
	}

	/* Debug. */
	/*ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
		"Authorization: %s", auth_line);*/

	/* If there is no aux auth info, then force a redirect if our conf directives say that we should */
        if (conf->cookie_auth_env_redirect && !strlen(aux_auth_info)) {
        	const char* redirect = conf->cookie_auth_env_redirect;
        	compose_and_set_redirect(r, redirect);
                return HTTP_MOVED_TEMPORARILY;
        }
        else {
	        /* Set fake auth_line. */
		if (auth_line) {
                	apr_table_set(r->headers_in, "Authorization", auth_line);
                }
	}

	/* Always return DECLINED because we don't authorize, */
	/* we just set things up for the next auth module to. */
    return DECLINED;
}
/**
 * Decrypt the string given as per the current config.
 *
 * Returns APR_SUCCESS if successful.
 */
static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f,
        session_crypto_dir_conf *dconf, const char *in, char **out)
{
    apr_status_t res;
    apr_crypto_key_t *key = NULL;
    apr_size_t ivSize = 0;
    apr_crypto_block_t *block = NULL;
    unsigned char *decrypted = NULL;
    apr_size_t decryptedlen, tlen;
    apr_size_t decodedlen;
    char *decoded;
    apr_size_t blockSize = 0;
    apr_crypto_block_key_type_e *cipher;
    int i = 0;

    /* strip base64 from the string */
    decoded = apr_palloc(r->pool, apr_base64_decode_len(in));
    decodedlen = apr_base64_decode(decoded, in);
    decoded[decodedlen] = '\0';

    res = crypt_init(r, f, &cipher, dconf);
    if (res != APR_SUCCESS) {
        return res;
    }

    /* try each passphrase in turn */
    for (; i < dconf->passphrases->nelts; i++) {
        const char *passphrase = APR_ARRAY_IDX(dconf->passphrases, i, char *);
        apr_size_t len = decodedlen;
        char *slider = decoded;

        /* encrypt using the first passphrase in the list */
        res = apr_crypto_passphrase(&key, &ivSize, passphrase,
                strlen(passphrase),
                (unsigned char *)decoded, sizeof(apr_uuid_t),
                *cipher, APR_MODE_CBC, 1, 4096, f, r->pool);
        if (APR_STATUS_IS_ENOKEY(res)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01832)
                    "the passphrase '%s' was empty", passphrase);
            continue;
        }
        else if (APR_STATUS_IS_EPADDING(res)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01833)
                    "padding is not supported for cipher");
            continue;
        }
        else if (APR_STATUS_IS_EKEYTYPE(res)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01834)
                    "the key type is not known");
            continue;
        }
        else if (APR_SUCCESS != res) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01835)
                    "encryption could not be configured.");
            continue;
        }

        /* sanity check - decoded too short? */
        if (decodedlen < (sizeof(apr_uuid_t) + ivSize)) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(01836)
                    "too short to decrypt, skipping");
            res = APR_ECRYPT;
            continue;
        }

        /* bypass the salt at the start of the decoded block */
        slider += sizeof(apr_uuid_t);
        len -= sizeof(apr_uuid_t);

        res = apr_crypto_block_decrypt_init(&block, &blockSize, (unsigned char *)slider, key,
                r->pool);
        if (APR_SUCCESS != res) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01837)
                    "apr_crypto_block_decrypt_init failed");
            continue;
        }

        /* bypass the iv at the start of the decoded block */
        slider += ivSize;
        len -= ivSize;

        /* decrypt the given string */
        res = apr_crypto_block_decrypt(&decrypted, &decryptedlen,
                (unsigned char *)slider, len, block);
        if (res) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01838)
                    "apr_crypto_block_decrypt failed");
            continue;
        }
        *out = (char *) decrypted;

        res = apr_crypto_block_decrypt_finish(decrypted + decryptedlen, &tlen, block);
        if (APR_SUCCESS != res) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01839)
                    "apr_crypto_block_decrypt_finish failed");
            continue;
        }
        decryptedlen += tlen;
        decrypted[decryptedlen] = 0;

        break;
    }

    if (APR_SUCCESS != res) {
        ap_log_rerror(APLOG_MARK, APLOG_INFO, res, r, APLOGNO(01840)
                "decryption failed");
    }

    return res;

}
void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
{
	#ifdef XML_PARSER_PERFORMANCE_TESTS
	XML_Timer timer( &endElementTime );
	#endif // XML_PARSER_PERFORMANCE_TESTS

	--mDepth;
	if (mSkipping)
	{
		if (mDepth < mSkipThrough)
		{
			mSkipping = false;
		}
		return;
	}
	
	Element element = readElement(name);
	
	switch (element)
	{
		case ELEMENT_LLSD:
			if (mInLLSDElement)
			{
				mInLLSDElement = false;
				mGracefullStop = true;
				XML_StopParser(mParser, false);
			}
			return;
	
		case ELEMENT_KEY:
			mCurrentKey = mCurrentContent;
			return;
			
		default:
			// all rest are values, fall through
			;
	}
	
	if (!mInLLSDElement) { return; }

	LLSD& value = *mStack.back();
	mStack.pop_back();
	
	switch (element)
	{
		case ELEMENT_UNDEF:
			value.clear();
			break;
		
		case ELEMENT_BOOL:
			value = (mCurrentContent == "true" || mCurrentContent == "1");
			break;
		
		case ELEMENT_INTEGER:
			{
				S32 i;
				// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
				if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
				{	// See if sscanf works - it's faster
					value = i;
				}
				else
				{
					value = LLSD(mCurrentContent).asInteger();
				}
			}
			break;
		
		case ELEMENT_REAL:
			{
				value = LLSD(mCurrentContent).asReal();
				// removed since this breaks when locale has decimal separator that isn't '.'
				// investigated changing local to something compatible each time but deemed higher
				// risk that just using LLSD.asReal() each time.
				//F64 r;
				//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
				//{	// See if sscanf works - it's faster
				//	value = r;
				//}
				//else
				//{
				//	value = LLSD(mCurrentContent).asReal();
				//}
			}
			break;
		
		case ELEMENT_STRING:
			value = mCurrentContent;
			break;
		
		case ELEMENT_UUID:
			value = LLSD(mCurrentContent).asUUID();
			break;
		
		case ELEMENT_DATE:
			value = LLSD(mCurrentContent).asDate();
			break;
		
		case ELEMENT_URI:
			value = LLSD(mCurrentContent).asURI();
			break;
		
		case ELEMENT_BINARY:
		{
			// Regex is expensive, but only fix for whitespace in base64,
			// created by python and other non-linden systems - DEV-39358
			// Fortunately we have very little binary passing now,
			// so performance impact shold be negligible. + poppy 2009-09-04
			boost::regex r;
			r.assign("\\s");
			std::string stripped = boost::regex_replace(mCurrentContent, r, "");
			S32 len = apr_base64_decode_len(stripped.c_str());
			std::vector<U8> data;
			data.resize(len);
			len = apr_base64_decode_binary(&data[0], stripped.c_str());
			data.resize(len);
			value = data;
			break;
		}
		
		case ELEMENT_UNKNOWN:
			value.clear();
			break;
			
		default:
			// other values, map and array, have already been set
			break;
	}

	mCurrentContent.clear();
}
Exemple #17
0
apr_status_t h2_session_start(h2_session *session)
{
    assert(session);
    /* Start the conversation by submitting our SETTINGS frame */
    apr_status_t status = APR_SUCCESS;
    h2_config *config = h2_config_get(session->c);
    int rv = 0;
    
    if (session->r) {
        /* 'h2c' mode: we should have a 'HTTP2-Settings' header with
         * base64 encoded client settings. */
        const char *s = apr_table_get(session->r->headers_in, "HTTP2-Settings");
        if (!s) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, session->r,
                          "HTTP2-Settings header missing in request");
            return APR_EINVAL;
        }
        int cslen = apr_base64_decode_len(s);
        char *cs = apr_pcalloc(session->r->pool, cslen);
        --cslen; /* apr also counts the terminating 0 */
        apr_base64_decode(cs, s);
        
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, session->r,
                      "upgrading h2c session with nghttp2 from %s (%d)",
                      s, cslen);
        
        rv = nghttp2_session_upgrade(session->ngh2, (uint8_t*)cs, cslen, NULL);
        if (rv != 0) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          "nghttp2_session_upgrade: %s", nghttp2_strerror(rv));
            return status;
        }
        
        /* Now we need to auto-open stream 1 for the request we got. */
        rv = stream_open(session, 1);
        if (rv != 0) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          "open stream 1: %s", nghttp2_strerror(rv));
            return status;
        }
        
        h2_stream * stream = h2_stream_set_get(session->streams, 1);
        if (stream == NULL) {
            status = APR_EGENERAL;
            ap_log_rerror(APLOG_MARK, APLOG_ERR, status, session->r,
                          "lookup of stream 1");
            return status;
        }
        
        status = h2_stream_rwrite(stream, session->r);
        if (status != APR_SUCCESS) {
            return status;
        }
        status = stream_end_headers(session, stream, 1);
        if (status != APR_SUCCESS) {
            return status;
        }
        status = h2_stream_write_eos(stream);
        if (status != APR_SUCCESS) {
            return status;
        }
    }

    nghttp2_settings_entry settings[] = {
        { NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
            h2_config_geti(config, H2_CONF_MAX_HL_SIZE) },
        { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
            h2_config_geti(config, H2_CONF_WIN_SIZE) },
        {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 
            h2_config_geti(config, H2_CONF_MAX_STREAMS) }, 
    };
    rv = nghttp2_submit_settings(session->ngh2, NGHTTP2_FLAG_NONE,
                                 settings,
                                 sizeof(settings)/sizeof(settings[0]));
    if (rv != 0) {
        status = APR_EGENERAL;
        ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c,
                      "nghttp2_submit_settings: %s", nghttp2_strerror(rv));
    }
    
    return status;
}
static int mag_auth(request_rec *req)
{
    const char *type;
    struct mag_config *cfg;
    const char *auth_header;
    char *auth_header_type;
    char *auth_header_value;
    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_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;
    uint32_t flags;
    uint32_t vtime;
    uint32_t maj, min;
    char *reply;
    size_t replen;
    char *clientname;
    gss_OID mech_type = GSS_C_NO_OID;
    gss_buffer_desc lname = GSS_C_EMPTY_BUFFER;
    struct mag_conn *mc = NULL;

    type = ap_auth_type(req);
    if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) {
        return DECLINED;
    }

    /* ignore auth for subrequests */
    if (!ap_is_initial_req(req)) {
        return OK;
    }

    cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module);

    if (cfg->ssl_only) {
        if (!mag_conn_is_https(req->connection)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 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|APLOG_NOERRNO, 0, req,
                          "Failed to retrieve connection context!");
            goto done;
        }
    }

    /* if available, session always supersedes connection bound data */
    mag_check_session(req, cfg, &mc);

    if (mc) {
        /* register the context in the memory pool, so it can be freed
         * when the connection/request is terminated */
        apr_pool_userdata_set(mc, "mag_conn_ptr",
                              mag_conn_destroy, mc->parent);

        if (mc->established) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
                          "Already established context found!");
            apr_table_set(req->subprocess_env, "GSS_NAME", mc->gss_name);
            req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate");
            req->user = apr_pstrdup(req->pool, mc->user_name);
            ret = OK;
            goto done;
        }
        pctx = &mc->ctx;
    } else {
        pctx = &ctx;
    }

    auth_header = apr_table_get(req->headers_in, "Authorization");
    if (!auth_header) goto done;

    auth_header_type = ap_getword_white(req->pool, &auth_header);
    if (!auth_header_type) goto done;

    if (strcasecmp(auth_header_type, "Negotiate") != 0) goto done;

    auth_header_value = ap_getword_white(req->pool, &auth_header);
    if (!auth_header_value) goto done;
    input.length = apr_base64_decode_len(auth_header_value) + 1;
    input.value = apr_pcalloc(req->pool, input.length);
    if (!input.value) goto done;
    input.length = apr_base64_decode(input.value, auth_header_value);

#ifdef HAVE_GSS_ACQUIRE_CRED_FROM
    if (cfg->use_s4u2proxy) {
        maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, 0,
                                    GSS_C_NO_OID_SET, GSS_C_BOTH,
                                    cfg->cred_store, &acquired_cred,
                                    NULL, NULL);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                          mag_error(req, "gss_acquire_cred_from() failed",
                                    maj, min));
            goto done;
        }
    }
#endif

    maj = gss_accept_sec_context(&min, pctx, acquired_cred,
                                 &input, GSS_C_NO_CHANNEL_BINDINGS,
                                 &client, &mech_type, &output, &flags, &vtime,
                                 &delegated_cred);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                      mag_error(req, "gss_accept_sec_context() failed",
                                maj, min));
        goto done;
    }

    if (maj == GSS_S_CONTINUE_NEEDED) {
        if (!mc) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
                          "Mechanism needs continuation but neither "
                          "GssapiConnectionBound nor "
                          "GssapiUseSessions are available");
            gss_delete_sec_context(&min, pctx, GSS_C_NO_BUFFER);
            gss_release_buffer(&min, &output);
            output.length = 0;
        }
        /* auth not complete send token and wait next packet */
        goto done;
    }

    req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate");

    /* Always set the GSS name in an env var */
    maj = gss_display_name(&min, client, &name, NULL);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                      mag_error(req, "gss_accept_sec_context() failed",
                                maj, min));
        goto done;
    }
    clientname = apr_pstrndup(req->pool, name.value, name.length);
    apr_table_set(req->subprocess_env, "GSS_NAME", clientname);

#ifdef HAVE_GSS_STORE_CRED_INTO
    if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
        char *ccachefile = NULL;

        mag_store_deleg_creds(req, cfg->deleg_ccache_dir, clientname,
                              delegated_cred, &ccachefile);

        if (ccachefile) {
            apr_table_set(req->subprocess_env, "KRB5CCNAME", ccachefile);
        }
    }
#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|APLOG_NOERRNO, 0, req, "%s",
                          mag_error(req, "gss_localname() failed", maj, min));
            goto done;
        }
        req->user = apr_pstrndup(req->pool, lname.value, lname.length);
    } else {
        req->user = clientname;
    }

    if (mc) {
        mc->user_name = apr_pstrdup(mc->parent, req->user);
        mc->gss_name = apr_pstrdup(mc->parent, clientname);
        mc->established = true;
        if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) {
            vtime = MIN_SESS_EXP_TIME;
        }
        mc->expiration = time(NULL) + vtime;
        mag_attempt_session(req, cfg, mc);
    }

    ret = OK;

done:
    if (ret == HTTP_UNAUTHORIZED) {
        if (output.length != 0) {
            replen = apr_base64_encode_len(output.length) + 1;
            reply = apr_pcalloc(req->pool, 10 + replen);
            if (reply) {
                memcpy(reply, "Negotiate ", 10);
                apr_base64_encode(&reply[10], output.value, output.length);
                apr_table_add(req->err_headers_out,
                              "WWW-Authenticate", reply);
            }
        } else {
            apr_table_add(req->err_headers_out,
                          "WWW-Authenticate", "Negotiate");
        }
    }
    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;
}
void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
{
	#ifdef XML_PARSER_PERFORMANCE_TESTS
	XML_Timer timer( &endElementTime );
	#endif // XML_PARSER_PERFORMANCE_TESTS

	--mDepth;
	if (mSkipping)
	{
		if (mDepth < mSkipThrough)
		{
			mSkipping = false;
		}
		return;
	}
	
	Element element = readElement(name);
	
	switch (element)
	{
		case ELEMENT_LLSD:
			if (mInLLSDElement)
			{
				mInLLSDElement = false;
				mGracefullStop = true;
				XML_StopParser(mParser, false);
			}
			return;
	
		case ELEMENT_KEY:
			mCurrentKey = mCurrentContent;
			return;
			
		default:
			// all rest are values, fall through
			;
	}
	
	if (!mInLLSDElement) { return; }

	LLSD& value = *mStack.back();
	mStack.pop_back();
	
	switch (element)
	{
		case ELEMENT_UNDEF:
			value.clear();
			break;
		
		case ELEMENT_BOOL:
			value = (mCurrentContent == "true" || mCurrentContent == "1");
			break;
		
		case ELEMENT_INTEGER:
			{
				S32 i;
				if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
				{	// See if sscanf works - it's faster
					value = i;
				}
				else
				{
					value = LLSD(mCurrentContent).asInteger();
				}
			}
			break;
		
		case ELEMENT_REAL:
			{
				F64 r;
				if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
				{	// See if sscanf works - it's faster
					value = r;
				}
				else
				{
					value = LLSD(mCurrentContent).asReal();
				}
			}
			break;
		
		case ELEMENT_STRING:
			value = mCurrentContent;
			break;
		
		case ELEMENT_UUID:
			value = LLSD(mCurrentContent).asUUID();
			break;
		
		case ELEMENT_DATE:
			value = LLSD(mCurrentContent).asDate();
			break;
		
		case ELEMENT_URI:
			value = LLSD(mCurrentContent).asURI();
			break;
		
		case ELEMENT_BINARY:
		{
			S32 len = apr_base64_decode_len(mCurrentContent.c_str());
			std::vector<U8> data;
			data.resize(len);
			len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
			data.resize(len);
			value = data;
			break;
		}
		
		case ELEMENT_UNKNOWN:
			value.clear();
			break;
			
		default:
			// other values, map and array, have already been set
			break;
	}

	mCurrentContent.clear();
}
Exemple #20
0
bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
{
	// binary: b##"ff3120ab1"
	// or: b(len)"..."

	// I want to manually control those values here to make sure the
	// parser doesn't break when someone changes a constant somewhere
	// else.
	const U32 BINARY_BUFFER_SIZE = 256;
	const U32 STREAM_GET_COUNT = 255;

	// need to read the base out.
	char buf[BINARY_BUFFER_SIZE];		/* Flawfinder: ignore */
	get(istr, buf, STREAM_GET_COUNT, '"');
	char c = get(istr);
	if(c != '"') return false;
	if(0 == strncmp("b(", buf, 2))
	{
		// We probably have a valid raw binary stream. determine
		// the size, and read it.
		S32 len = strtol(buf + 2, NULL, 0);
		if(mCheckLimits && (len > mMaxBytesLeft)) return false;
		std::vector<U8> value;
		if(len)
		{
			value.resize(len);
			account(fullread(istr, (char *)&value[0], len));
		}
		c = get(istr); // strip off the trailing double-quote
		data = value;
	}
	else if(0 == strncmp("b64", buf, 3))
	{
		// *FIX: A bit inefficient, but works for now. To make the
		// format better, I would need to add a hint into the
		// serialization format that indicated how long it was.
		std::stringstream coded_stream;
		get(istr, *(coded_stream.rdbuf()), '\"');
		c = get(istr);
		std::string encoded(coded_stream.str());
		S32 len = apr_base64_decode_len(encoded.c_str());
		std::vector<U8> value;
		if(len)
		{
			value.resize(len);
			len = apr_base64_decode_binary(&value[0], encoded.c_str());
			value.resize(len);
		}
		data = value;
	}
	else if(0 == strncmp("b16", buf, 3))
	{
		// yay, base 16. We pop the next character which is either a
		// double quote or base 16 data. If it's a double quote, we're
		// done parsing. If it's not, put the data back, and read the
		// stream until the next double quote.
		char* read;	 /*Flawfinder: ignore*/
		U8 byte;
		U8 byte_buffer[BINARY_BUFFER_SIZE];
		U8* write;
		std::vector<U8> value;
		c = get(istr);
		while(c != '"')
		{
			putback(istr, c);
			read = buf;
			write = byte_buffer;
			get(istr, buf, STREAM_GET_COUNT, '"');
			c = get(istr);
			while(*read != '\0')	 /*Flawfinder: ignore*/
			{
				byte = hex_as_nybble(*read++);
				byte = byte << 4;
				byte |= hex_as_nybble(*read++);
				*write++ = byte;
			}
			// copy the data out of the byte buffer
			value.insert(value.end(), byte_buffer, write);
		}
		data = value;
	}
	else
	{
		return false;
	}
	return true;
}
Exemple #21
0
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);

    /* ccname */
    mc->ccname = apr_pstrndup(mc->pool,
                              (char *)gsessdata->ccname.buf,
                              gsessdata->ccname.size);
    if (!mc->ccname) goto done;

    /* OK we have a valid token */
    mc->established = true;

done:
    ASN_STRUCT_FREE(asn_DEF_GSSSessionData, gsessdata);
}