char * ipr_file_digest ( char * filename // File to digest ) { FILE *file_stream; // File stream to digest ipr_bucket_t *bucket; // Bucket of data from file apr_sha1_ctx_t context; apr_byte_t bin_digest [APR_SHA1_DIGESTSIZE]; char * digest = NULL; // Not documented // assert (filename); # define DIGEST_BLOCK 1000000 // Read 1MB at a time from file file_stream = fopen (filename, "rb"); if (file_stream) { apr_sha1_init (&context); bucket = ipr_bucket_new (DIGEST_BLOCK); while ((bucket->cur_size = fread (bucket->data, 1, DIGEST_BLOCK, file_stream)) > 0) apr_sha1_update (&context, (char *) bucket->data, bucket->cur_size); fclose (file_stream); ipr_bucket_destroy (&bucket); apr_sha1_final (bin_digest, &context); digest = icl_mem_alloc (ICL_SHORTSTR_MAX); apr_base64_encode (digest, (char *) bin_digest, APR_MD5_DIGESTSIZE); } return (digest); }
void mag_attempt_session(request_rec *req, struct mag_config *cfg, struct mag_conn *mc) { session_rec *sess = NULL; char *sessval = NULL; struct databuf plainbuf = { 0 }; struct databuf cipherbuf = { 0 }; struct databuf ctxbuf = { 0 }; apr_status_t rc; /* 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, generating new one."); rc = SEAL_KEY_CREATE(cfg->pool, &cfg->mag_skey, NULL); if (rc != OK) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "Failed to create sealing key!"); return; } } sessval = apr_psprintf(req->pool, "%ld:%s:%s", (long)mc->expiration, mc->user_name, mc->gss_name); if (!sessval) return; plainbuf.length = strlen(sessval) + 1; plainbuf.value = (unsigned char *)sessval; 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!"); return; } ctxbuf.length = apr_base64_encode_len(cipherbuf.length); ctxbuf.value = apr_pcalloc(req->pool, ctxbuf.length); if (!ctxbuf.value) return; 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!"); return; } }
const char *serf_ssl_cert_export( const serf_ssl_certificate_t *cert, apr_pool_t *pool) { char *binary_cert; char *encoded_cert; int len; unsigned char *unused; /* find the length of the DER encoding. */ len = i2d_X509(cert->ssl_cert, NULL); if (len < 0) { return NULL; } binary_cert = apr_palloc(pool, len); unused = (unsigned char *)binary_cert; len = i2d_X509(cert->ssl_cert, &unused); /* unused is incremented */ if (len < 0) { return NULL; } encoded_cert = apr_palloc(pool, apr_base64_encode_len(len)); apr_base64_encode(encoded_cert, binary_cert, len); return encoded_cert; }
/* * base64url encode a string */ int apr_jwt_base64url_encode(apr_pool_t *pool, char **dst, const char *src, int src_len, int padding) { if ((src == NULL) || (src_len <= 0)) return -1; int enc_len = apr_base64_encode_len(src_len); char *enc = apr_palloc(pool, enc_len); apr_base64_encode(enc, (const char *) src, src_len); int i = 0; while (enc[i] != '\0') { if (enc[i] == '+') enc[i] = '-'; if (enc[i] == '/') enc[i] = '_'; if (enc[i] == '=') { if (padding == 1) { enc[i] = ','; } else { enc[i] = '\0'; enc_len--; } } i++; } *dst = enc; return enc_len; }
int lua_apr_base64_encode(lua_State *L) { size_t plain_len, coded_len; apr_pool_t *memory_pool; const char *plain; char *coded; memory_pool = to_pool(L); plain = luaL_checklstring(L, 1, &plain_len); coded_len = apr_base64_encode_len(plain_len); coded = apr_palloc(memory_pool, coded_len); if (coded == NULL) return push_error_memory(L); coded_len = apr_base64_encode(coded, plain, plain_len); if (coded_len > 0 && coded[coded_len - 1] == '\0') coded_len--; lua_pushlstring(L, coded, coded_len); return 1; }
/** * base64 encode the authentication data and build an authentication * header in this format: * [PROTOCOL] [BASE64 AUTH DATA] */ void svn_ra_serf__encode_auth_header(const char * protocol, char **header, const char * data, apr_size_t data_len, apr_pool_t *pool) { apr_size_t encoded_len, proto_len; char * ptr; encoded_len = apr_base64_encode_len(data_len); proto_len = strlen(protocol); *header = apr_palloc(pool, encoded_len + proto_len + 1); ptr = *header; apr_cpystrn(ptr, protocol, proto_len + 1); ptr += proto_len; *ptr++ = ' '; apr_base64_encode(ptr, data, data_len); }
/** * base64 encode the authentication data and build an authentication * header in this format: * [SCHEME] [BASE64 of auth DATA] */ void serf__encode_auth_header(const char **header, const char *scheme, const char *data, apr_size_t data_len, apr_pool_t *pool) { apr_size_t encoded_len, scheme_len; char *ptr; encoded_len = apr_base64_encode_len(data_len); scheme_len = strlen(scheme); ptr = apr_palloc(pool, encoded_len + scheme_len + 1); *header = ptr; apr_cpystrn(ptr, scheme, scheme_len + 1); ptr += scheme_len; *ptr++ = ' '; apr_base64_encode(ptr, data, data_len); }
/* function to fix any headers in the input request that may be relied on by an application. e.g. php uses the Authorization header when logging the request in apache and not r->user (like it ought to). It is applied after the request has been authenticated. */ static void fix_headers_in(request_rec *r, const char *szPassword) { strAuth_memCookie_config_rec *conf = NULL; const char *szUser = NULL; /* Set an Authorization header in the input request table for php and other applications that use it to obtain the username (mainly to fix apache logging of php scripts). We only set this if there is no header already present. */ if (apr_table_get(r->headers_in, "Authorization") == NULL) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r, ERRTAG "fixing apache Authorization header for this request using user:%s",r->user); /* concat username and ':' */ if (szPassword != NULL) szUser = apr_pstrcat(r->pool, r->user, ":", szPassword, NULL); else szUser = apr_pstrcat(r->pool, r->user, ":", NULL); /* alloc memory for the estimated encode size of the username */ char *szB64_enc_user = apr_palloc(r->pool, apr_base64_encode_len(strlen(szUser)) + 1); if (!szB64_enc_user) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, ERRTAG "memory alloc failed!"); return; } /* encode username in base64 format */ apr_base64_encode(szB64_enc_user, szUser, strlen(szUser)); /* set authorization header */ apr_table_set(r->headers_in, "Authorization", apr_pstrcat(r->pool, "Basic ", szB64_enc_user, NULL)); /* force auth type to basic */ r->ap_auth_type = apr_pstrdup(r->pool, "Basic"); } return; }
// helper function used for sending prepared data to socket for authorization against dovecot auth int send_auth_request(apr_pool_t * p, request_rec * r, int sock, const char *user, const char *pass, char *remotehost) { struct iovec concat[4]; size_t const up_size = strlen(user) + strlen(pass) + 2; if (up_size > BUFFMAX - 1024) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Dovecot Authentication: User and pass length is over (or close) BUFFMAX=%i which is NOT allowed size=%u\n", BUFFMAX, (unsigned int)up_size); return 0; } size_t const eup_size = apr_base64_encode_len(up_size); char * const encoded_user_pass = (char *)apr_palloc(p, sizeof(char) * eup_size); ap_assert(encoded_user_pass != NULL); // this beautifull code snippet from bellow (concat blah blah) is needed for use of apr_pstrcatv // as without using apr_pstrcatv apr_pstrcat will remove \0 which we need for creating base64 encoded user_pass combination... concat[0].iov_base = (void *)"\0"; concat[0].iov_len = 1; concat[1].iov_base = (void *)user; concat[1].iov_len = strlen(user); concat[2].iov_base = (void *)"\0"; concat[2].iov_len = 1; concat[3].iov_base = (void *)pass; concat[3].iov_len = strlen(pass); char * const user_pass = apr_pstrcatv(p, concat, 4, NULL); ap_assert(user_pass != NULL); apr_base64_encode(encoded_user_pass, user_pass, up_size); char * const data = apr_psprintf(p, "AUTH\t1\tPLAIN\tservice=apache\tnologin" // local ip (lip) is hardcoded as we are using local unix socket anyway... "\tlip=127.0.0.1\trip=%s\tsecured\tresp=%s\n", remotehost, encoded_user_pass); ap_assert(data != NULL); size_t const d_size = strlen(data); if (send(sock, data, d_size, 0) > 0) { // scrub user credentials memset(user_pass, '\0', up_size); memset(encoded_user_pass, '\0', eup_size); memset(data, '\0', d_size); return 1; } else { return 0; } }
static char* get_encoded_string(request_rec *r, const char* str) { char* buf; int len; if (!str) { return NULL; } #ifdef MEMC_KEY_ENCODING_BASE64 len = apr_base64_encode_len( strlen(str) ); buf = (char *) apr_palloc( r->pool, len + 1 ); if(!buf){ ILLOG_ERROR(r, MODTAG "memory alloc failed!"); return NULL; } apr_base64_encode(buf,str,strlen(str)); return buf; #else len = APR_MD5_DIGESTSIZE; buf = (unsigned char*) apr_palloc( r->pool, len + 1); apr_md5(buf, str, strlen(str)); return conv2hex(r,(const unsigned char *)buf,APR_MD5_DIGESTSIZE); #endif }
static char * alloc_cookie_id(request_rec *r) { char *cookie_id; char *uuid_string; unsigned char *md5_value; apr_uuid_t uuid; apr_status_t retval; apr_uuid_get(&uuid); uuid_string = apr_palloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1); memset(uuid_string, 0, APR_UUID_FORMATTED_LENGTH + 1); apr_uuid_format(uuid_string, &uuid);; md5_value = (unsigned char*)apr_palloc(r->pool, APR_MD5_DIGESTSIZE + 1); memset(md5_value, 0, APR_MD5_DIGESTSIZE + 1); retval = apr_md5(md5_value, (const char*)uuid_string, APR_UUID_FORMATTED_LENGTH); if (retval != APR_SUCCESS) { ERR(r, "md5 failed."); return NULL; } cookie_id = apr_palloc(r->pool, apr_base64_encode_len(APR_MD5_DIGESTSIZE)+1); memset(cookie_id, 0, APR_MD5_DIGESTSIZE+1); apr_base64_encode(cookie_id, (char*)md5_value, APR_MD5_DIGESTSIZE); DBG(r, "cookie_id=[%s]", cookie_id); cookie_id = chxj_url_encode(r->pool,cookie_id); DBG(r, "cookie_id=[%s]", cookie_id); return cookie_id; }
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; }
/* This function populates the subprocess environment with data received * from the IdP. * * Parameters: * request_rec *r The request we should add the data to. * am_cache_entry_t *t The session data. * * Returns: * Nothing. */ void am_cache_env_populate(request_rec *r, am_cache_entry_t *t) { am_dir_cfg_rec *d; int i; apr_hash_t *counters; am_envattr_conf_t *env_varname_conf; const char *varname; const char *varname_prefix; const char *value; int *count; int status; d = am_get_dir_cfg(r); /* Check if the user attribute has been set, and set it if it * hasn't been set. */ if (am_cache_entry_slot_is_empty(&t->user)) { for(i = 0; i < t->size; ++i) { varname = am_cache_entry_get_string(t, &t->env[i].varname); if (strcmp(varname, d->userattr) == 0) { value = am_cache_entry_get_string(t, &t->env[i].value); status = am_cache_entry_store_string(t, &t->user, value); if (status != 0) { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "Unable to store the user name because there" " is no more space in the session. " "Username = \"%s\".", value); } } } } /* Allocate a set of counters for duplicate variables in the list. */ counters = apr_hash_make(r->pool); /* Populate the subprocess environment with the attributes we * received from the IdP. */ for(i = 0; i < t->size; ++i) { varname = am_cache_entry_get_string(t, &t->env[i].varname); varname_prefix = "MELLON_"; /* Check if we should map this name into another name. */ env_varname_conf = (am_envattr_conf_t *)apr_hash_get( d->envattr, varname, APR_HASH_KEY_STRING); if(env_varname_conf != NULL) { varname = env_varname_conf->name; if (!env_varname_conf->prefixed) { varname_prefix = ""; } } value = am_cache_entry_get_string(t, &t->env[i].value); /* * If we find a variable remapping to MellonUser, use it. */ if (am_cache_entry_slot_is_empty(&t->user) && (strcmp(varname, d->userattr) == 0)) { status = am_cache_entry_store_string(t, &t->user, value); if (status != 0) { ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "Unable to store the user name because there" " is no more space in the session. " "Username = \"%s\".", value); } } /* Find the number of times this variable has been set. */ count = apr_hash_get(counters, varname, APR_HASH_KEY_STRING); if(count == NULL) { /* This is the first time. Create a counter for this variable. */ count = apr_palloc(r->pool, sizeof(int)); *count = 0; apr_hash_set(counters, varname, APR_HASH_KEY_STRING, count); /* Add the variable without a suffix. */ apr_table_set(r->subprocess_env, apr_pstrcat(r->pool, varname_prefix, varname, NULL), value); } /* Add the variable with a suffix indicating how many times it has * been added before. */ apr_table_set(r->subprocess_env, apr_psprintf(r->pool, "%s%s_%d", varname_prefix, varname, *count), value); /* Increase the count. */ ++(*count); } if (!am_cache_entry_slot_is_empty(&t->user)) { /* We have a user-"name". Set r->user and r->ap_auth_type. */ r->user = apr_pstrdup(r->pool, am_cache_entry_get_string(t, &t->user)); r->ap_auth_type = apr_pstrdup(r->pool, "Mellon"); } else { /* We don't have a user-"name". Log error. */ ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "Didn't find the attribute \"%s\" in the attributes" " which were received from the IdP. Cannot set a user" " for this request without a valid user attribute.", d->userattr); } /* Populate with the session? */ if (d->dump_session) { char *session; const char *srcstr; int srclen, dstlen; srcstr = am_cache_entry_get_string(t, &t->lasso_session); srclen = strlen(srcstr); dstlen = apr_base64_encode_len(srclen); session = apr_palloc(r->pool, dstlen); (void)apr_base64_encode(session, srcstr, srclen); apr_table_set(r->subprocess_env, "MELLON_SESSION", session); } if (d->dump_saml_response) { const char *sr = am_cache_entry_get_string(t, &t->lasso_saml_response); if (sr) { apr_table_set(r->subprocess_env, "MELLON_SAML_RESPONSE", sr); } } }
void *APR_THREAD_FUNC tcp_proxy_run(apr_thread_t * thread, void *data) { char buffer[64]; TcpProxyData *tpd = (TcpProxyData *) data; if (tpd != NULL) { request_rec *r = (tpd->server)->request(tpd->server); APACHELOG(APLOG_DEBUG, r, "tcp_proxy_run start"); /* Keep sending messages as long as the connection is active */ while (tpd->active && tpd->tcpsocket) { #define WSTCPBUFSIZ 1024 #define WSTCPCBUFSIZ ((WSTCPBUFSIZ*4/3)+5) char buf[WSTCPBUFSIZ]; char cbuf[WSTCPCBUFSIZ]; apr_size_t len = sizeof(buf); apr_status_t rv; rv = apr_socket_recv(tpd->tcpsocket, buf, &len); if ( APR_STATUS_IS_TIMEUP(rv)) { /* nothing was read this time round. */ continue; } else if (rv != APR_SUCCESS && !APR_STATUS_IS_EOF(rv)) { /* we've received an unexpected result value, so we want to log that. */ char s[1024]; apr_strerror(rv, s, sizeof(s)); APACHELOG(APLOG_DEBUG, r, "tcp_proxy_range_run apr_socket_recv failed len=%lu rv=%d, %s", (unsigned long) len, rv, s); } if ( rv != APR_SUCCESS ) { /* our read was not successful, shutdown now! */ tcp_proxy_range_shutdown_socket(tpd); tpd->server->close(tpd->server); break; } size_t towrite = len; char *wbuf = buf; /* Base64 encode it if necessary */ if (tpd->base64) { towrite = apr_base64_encode(cbuf, buf, towrite); wbuf = cbuf; } size_t written = tpd->server->send(tpd->server, MESSAGE_TYPE_TEXT /* FIXME */ , (unsigned char *) wbuf, towrite); if (written != towrite) { APACHELOG(APLOG_DEBUG, r, "tcp_proxy_run send failed, wrote %lu bytes of %lu", (unsigned long) written, (unsigned long) len); tcp_proxy_shutdown_socket(tpd); tpd->server->close(tpd->server); break; } } APACHELOG(APLOG_DEBUG, r, "tcp_proxy_run stop"); } return NULL; }
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; if (sess->expiry != 0) { mc->expiration = mc->expiration < apr_time_sec(sess->expiry) ? mc->expiration : apr_time_sec(sess->expiry); } 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; /* NULL ccname here just means default ccache */ if (mc->ccname && OCTET_STRING_fromString(&gsessdata.ccname, mc->ccname) != 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_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) { char *ccache_path; mc->ccname = 0; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req, "requester: %s", mc->gss_name); ccache_path = get_ccache_name(req, cfg->deleg_ccache_dir, mc->gss_name, cfg->deleg_ccache_unique, mc); if (ccache_path == NULL) { goto done; } mag_store_deleg_creds(req, ccache_path, delegated_cred); mc->delegated = true; if (!req_cfg->use_sessions && cfg->deleg_ccache_unique) { /* queue removing ccache to avoid littering filesystem */ apr_pool_cleanup_register(mc->pool, ccache_path, (int (*)(void *)) unlink, apr_pool_cleanup_null); } /* extract filename from full path */ mc->ccname = strrchr(ccache_path, '/') + 1; } #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; }
/** * Encrypt the string given as per the current config. * * Returns APR_SUCCESS if successful. */ static apr_status_t encrypt_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 *encrypt = NULL; unsigned char *combined = NULL; apr_size_t encryptlen, tlen; char *base64; apr_size_t blockSize = 0; const unsigned char *iv = NULL; apr_uuid_t salt; apr_crypto_block_key_type_e *cipher; const char *passphrase; /* by default, return an empty string */ *out = ""; /* don't attempt to encrypt an empty string, trying to do so causes a segfault */ if (!in || !*in) { return APR_SUCCESS; } /* use a uuid as a salt value, and prepend it to our result */ apr_uuid_get(&salt); res = crypt_init(r, f, &cipher, dconf); if (res != APR_SUCCESS) { return res; } /* encrypt using the first passphrase in the list */ passphrase = APR_ARRAY_IDX(dconf->passphrases, 0, char *); res = apr_crypto_passphrase(&key, &ivSize, passphrase, strlen(passphrase), (unsigned char *) (&salt), 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_ERR, res, r, APLOGNO(01825) "the passphrase '%s' was empty", passphrase); } if (APR_STATUS_IS_EPADDING(res)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01826) "padding is not supported for cipher"); } if (APR_STATUS_IS_EKEYTYPE(res)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01827) "the key type is not known"); } if (APR_SUCCESS != res) { ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01828) "encryption could not be configured."); return res; } res = apr_crypto_block_encrypt_init(&block, &iv, key, &blockSize, r->pool); if (APR_SUCCESS != res) { ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01829) "apr_crypto_block_encrypt_init failed"); return res; } /* encrypt the given string */ res = apr_crypto_block_encrypt(&encrypt, &encryptlen, (unsigned char *)in, strlen(in), block); if (APR_SUCCESS != res) { ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01830) "apr_crypto_block_encrypt failed"); return res; } res = apr_crypto_block_encrypt_finish(encrypt + encryptlen, &tlen, block); if (APR_SUCCESS != res) { ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01831) "apr_crypto_block_encrypt_finish failed"); return res; } encryptlen += tlen; /* prepend the salt and the iv to the result */ combined = apr_palloc(r->pool, ivSize + encryptlen + sizeof(apr_uuid_t)); memcpy(combined, &salt, sizeof(apr_uuid_t)); memcpy(combined + sizeof(apr_uuid_t), iv, ivSize); memcpy(combined + sizeof(apr_uuid_t) + ivSize, encrypt, encryptlen); /* base64 encode the result */ base64 = apr_palloc(r->pool, apr_base64_encode_len(ivSize + encryptlen + sizeof(apr_uuid_t) + 1) * sizeof(char)); apr_base64_encode(base64, (const char *) combined, ivSize + encryptlen + sizeof(apr_uuid_t)); *out = base64; return res; }
int main(int argc, const char **argv) { apr_status_t status; apr_pool_t *pool; apr_sockaddr_t *address; serf_context_t *context; serf_connection_t *connection; app_baton_t app_ctx; handler_baton_t *handler_ctx; apr_uri_t url; const char *raw_url, *method; int count; apr_getopt_t *opt; char opt_c; char *authn = NULL; const char *opt_arg; /* For the parser threads */ apr_thread_t *thread[3]; apr_threadattr_t *tattr; apr_status_t parser_status; parser_baton_t *parser_ctx; apr_initialize(); atexit(apr_terminate); apr_pool_create(&pool, NULL); apr_atomic_init(pool); /* serf_initialize(); */ /* Default to one round of fetching. */ count = 1; /* Default to GET. */ method = "GET"; apr_getopt_init(&opt, pool, argc, argv); while ((status = apr_getopt(opt, "a:hv", &opt_c, &opt_arg)) == APR_SUCCESS) { int srclen, enclen; switch (opt_c) { case 'a': srclen = strlen(opt_arg); enclen = apr_base64_encode_len(srclen); authn = apr_palloc(pool, enclen + 6); strcpy(authn, "Basic "); (void) apr_base64_encode(&authn[6], opt_arg, srclen); break; case 'h': print_usage(pool); exit(0); break; case 'v': puts("Serf version: " SERF_VERSION_STRING); exit(0); default: break; } } if (opt->ind != opt->argc - 1) { print_usage(pool); exit(-1); } raw_url = argv[opt->ind]; apr_uri_parse(pool, raw_url, &url); if (!url.port) { url.port = apr_uri_port_of_scheme(url.scheme); } if (!url.path) { url.path = "/"; } if (strcasecmp(url.scheme, "https") == 0) { app_ctx.using_ssl = 1; } else { app_ctx.using_ssl = 0; } status = apr_sockaddr_info_get(&address, url.hostname, APR_UNSPEC, url.port, 0, pool); if (status) { printf("Error creating address: %d\n", status); exit(1); } context = serf_context_create(pool); /* ### Connection or Context should have an allocator? */ app_ctx.bkt_alloc = serf_bucket_allocator_create(pool, NULL, NULL); app_ctx.ssl_ctx = NULL; app_ctx.authn = authn; connection = serf_connection_create(context, address, conn_setup, &app_ctx, closed_connection, &app_ctx, pool); handler_ctx = (handler_baton_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc, sizeof(handler_baton_t)); handler_ctx->allocator = app_ctx.bkt_alloc; handler_ctx->doc_queue = apr_array_make(pool, 1, sizeof(doc_path_t*)); handler_ctx->doc_queue_alloc = app_ctx.bkt_alloc; handler_ctx->requests_outstanding = (apr_uint32_t*)serf_bucket_mem_alloc(app_ctx.bkt_alloc, sizeof(apr_uint32_t)); apr_atomic_set32(handler_ctx->requests_outstanding, 0); handler_ctx->hdr_read = 0; parser_ctx = (void*)serf_bucket_mem_alloc(app_ctx.bkt_alloc, sizeof(parser_baton_t)); parser_ctx->requests_outstanding = handler_ctx->requests_outstanding; parser_ctx->connection = connection; parser_ctx->app_ctx = &app_ctx; parser_ctx->doc_queue = handler_ctx->doc_queue; parser_ctx->doc_queue_alloc = handler_ctx->doc_queue_alloc; /* Restrict ourselves to this host. */ parser_ctx->hostinfo = url.hostinfo; status = apr_thread_mutex_create(&parser_ctx->mutex, APR_THREAD_MUTEX_DEFAULT, pool); if (status) { printf("Couldn't create mutex %d\n", status); return status; } status = apr_thread_cond_create(&parser_ctx->condvar, pool); if (status) { printf("Couldn't create condvar: %d\n", status); return status; } /* Let the handler now which condvar to use. */ handler_ctx->doc_queue_condvar = parser_ctx->condvar; apr_threadattr_create(&tattr, pool); /* Start the parser thread. */ apr_thread_create(&thread[0], tattr, parser_thread, parser_ctx, pool); /* Deliver the first request. */ create_request(url.hostinfo, url.path, NULL, NULL, parser_ctx, pool); /* Go run our normal thread. */ while (1) { int tries = 0; status = serf_context_run(context, SERF_DURATION_FOREVER, pool); if (APR_STATUS_IS_TIMEUP(status)) continue; if (status) { char buf[200]; printf("Error running context: (%d) %s\n", status, apr_strerror(status, buf, sizeof(buf))); exit(1); } /* We run this check to allow our parser threads to add more * requests to our queue. */ for (tries = 0; tries < 3; tries++) { if (!apr_atomic_read32(handler_ctx->requests_outstanding)) { #ifdef SERF_VERBOSE printf("Waiting..."); #endif apr_sleep(100000); #ifdef SERF_VERBOSE printf("Done\n"); #endif } else { break; } } if (tries >= 3) { break; } /* Debugging purposes only! */ serf_debug__closed_conn(app_ctx.bkt_alloc); } printf("Quitting...\n"); serf_connection_close(connection); /* wake up the parser via condvar signal */ apr_thread_cond_signal(parser_ctx->condvar); status = apr_thread_join(&parser_status, thread[0]); if (status) { printf("Error joining thread: %d\n", status); return status; } serf_bucket_mem_free(app_ctx.bkt_alloc, handler_ctx->requests_outstanding); serf_bucket_mem_free(app_ctx.bkt_alloc, parser_ctx); apr_pool_destroy(pool); return 0; }
static ngx_http_modsecurity_ctx_t * ngx_http_modsecurity_create_ctx(ngx_http_request_t *r) { ngx_http_modsecurity_loc_conf_t *cf; ngx_pool_cleanup_t *cln; ngx_http_modsecurity_ctx_t *ctx; apr_sockaddr_t *asa; struct sockaddr_in *sin; char *txid; unsigned char salt[TXID_SIZE]; int i; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_modsecurity_ctx_t)); if (ctx == NULL) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "modSecurity: ctx memory allocation error"); return NULL; } cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_modsecurity_ctx_t)); if (cln == NULL) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "modSecurity: ctx memory allocation error"); return NULL; } cln->handler = ngx_http_modsecurity_cleanup; cln->data = ctx; ctx->r = r; if (r->connection->requests == 0 || ctx->connection == NULL) { /* TODO: set server_rec, why igonre return value? */ ctx->connection = modsecNewConnection(); /* fill apr_sockaddr_t */ asa = ngx_palloc(r->pool, sizeof(apr_sockaddr_t)); asa->pool = ctx->connection->pool; asa->hostname = (char *)ngx_pstrdup0(r->pool, &r->connection->addr_text); asa->servname = asa->hostname; asa->next = NULL; asa->salen = r->connection->socklen; ngx_memcpy(&asa->sa, r->connection->sockaddr, asa->salen); asa->family = ((struct sockaddr *)&asa->sa)->sa_family; switch ( asa->family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *)&asa->sa; asa->ipaddr_ptr = &sin6->sin6_addr; asa->ipaddr_len = sizeof(sin6->sin6_addr); asa->port = ntohs(sin6->sin6_port); asa->addr_str_len = NGX_INET6_ADDRSTRLEN + 1; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) &asa->sa; asa->ipaddr_ptr = &sin->sin_addr; asa->ipaddr_len = sizeof(sin->sin_addr); asa->port = ntohs(sin->sin_port); asa->addr_str_len = NGX_INET_ADDRSTRLEN + 1; break; } #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3 ctx->connection->remote_addr = asa; ctx->connection->remote_ip = asa->hostname; #else ctx->connection->client_addr = asa; ctx->connection->client_ip = asa->hostname; #endif ctx->connection->remote_host = NULL; modsecProcessConnection(ctx->connection); } cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity); ctx->req = modsecNewRequest(ctx->connection, cf->config); apr_table_setn(ctx->req->notes, NOTE_NGINX_REQUEST_CTX, (const char *) ctx); apr_generate_random_bytes(salt, TXID_SIZE); txid = apr_pcalloc (ctx->req->pool, TXID_SIZE); apr_base64_encode (txid, (const char*)salt, TXID_SIZE); for(i=0;i<TXID_SIZE;i++) { if((salt[i] >= 0x30) && (salt[i] <= 0x39)) {} else if((salt[i] >= 0x40) && (salt[i] <= 0x5A)) {} else if((salt[i] >= 0x61) && (salt[i] <= 0x7A)) {} else { if((i%2)==0) salt[i] = 0x41; else salt[i] = 0x63; } } salt[TXID_SIZE-1] = '\0'; apr_table_setn(ctx->req->subprocess_env, "UNIQUE_ID", apr_psprintf(ctx->req->pool, "%s", salt)); ctx->brigade = apr_brigade_create(ctx->req->pool, ctx->req->connection->bucket_alloc); if (ctx->brigade == NULL) { return NULL; } return ctx; }