Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F62653479
mod_tequila.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, May 14, 15:20
Size
59 KB
Mime Type
text/x-c
Expires
Thu, May 16, 15:20 (2 d)
Engine
blob
Format
Raw Data
Handle
17673375
Attached To
R6407 Tequila Apache module
mod_tequila.c
View Options
//
//
// Apache module for Tequila authentication tool.
// Version 2.0.2
//
//
#include <httpd.h>
#include <http_log.h>
#include <http_core.h>
#include <http_config.h>
#include <http_protocol.h>
#ifdef APACHE2
# include <apr_strings.h>
# include <ap_config.h>
# include <apr_lib.h>
#endif
#ifdef USESSL
# include <string.h>
# include "openssl/bio.h"
# include "openssl/ssl.h"
# include "openssl/err.h"
# include "openssl/x509v3.h"
#endif
#include "mod_tequila.h"
static
int
createserverrequest
(
request_rec
*
r
);
static
Session
*
fetchattributes
(
request_rec
*
r
,
const
char
*
requestkey
);
static
void
substsepar
(
char
*
string
,
char
oldsepar
,
char
newsepar
);
static
char
*
unescape_url
(
AP_POOL
*
p
,
const
char
*
url
);
static
int
setenvvars
(
request_rec
*
r
);
static
void
error
(
request_rec
*
r
,
char
*
msg
);
static
void
writeline
(
AP_FILE_T
fp
,
char
*
string
);
#ifdef APACHE2
#include <sys/stat.h>
static
apr_global_mutex_t
*
tequila_log_lock
=
NULL
;
static
const
command_rec
command_table
[]
=
{
AP_INIT_TAKE1
(
"TequilaRewrite"
,
cmd_rewrite
,
NULL
,
OR_FILEINFO
,
"Rewrite"
),
AP_INIT_RAW_ARGS
(
"TequilaAllowIf"
,
cmd_allowif
,
NULL
,
OR_AUTHCFG
,
"Access condition"
),
AP_INIT_RAW_ARGS
(
"TequilaRequest"
,
cmd_request
,
NULL
,
OR_AUTHCFG
,
"Request"
),
AP_INIT_RAW_ARGS
(
"TequilaAllowNet"
,
cmd_allownet
,
NULL
,
OR_AUTHCFG
,
"Allowed Net"
),
AP_INIT_RAW_ARGS
(
"TequilaAllows"
,
cmd_allows
,
NULL
,
OR_AUTHCFG
,
"Allows attribute"
),
AP_INIT_TAKE1
(
"TequilaService"
,
cmd_service
,
NULL
,
OR_AUTHCFG
,
"Service name"
),
AP_INIT_TAKE1
(
"TequilaResource"
,
cmd_resource
,
NULL
,
OR_AUTHCFG
,
"Tequila resource"
),
AP_INIT_TAKE1
(
"TequilaKeyFile"
,
cmd_sslkeyfile
,
NULL
,
OR_AUTHCFG
,
"SSL Key file"
),
AP_INIT_TAKE1
(
"TequilaCertFile"
,
cmd_sslcertfile
,
NULL
,
OR_AUTHCFG
,
"SSL Cert file"
),
AP_INIT_TAKE1
(
"TequilaServer"
,
cmd_server
,
NULL
,
RSRC_CONF
,
"Tequila server"
),
AP_INIT_TAKE1
(
"TequilaSessionDir"
,
cmd_sessdir
,
NULL
,
RSRC_CONF
,
"Session directory"
),
AP_INIT_TAKE1
(
"TequilaSessionMax"
,
cmd_sessmax
,
NULL
,
RSRC_CONF
,
"Session duration"
),
AP_INIT_TAKE1
(
"TequilaLog"
,
cmd_log
,
NULL
,
RSRC_CONF
,
"Logfile"
),
AP_INIT_TAKE1
(
"TequilaLogLevel"
,
cmd_loglevel
,
NULL
,
RSRC_CONF
,
"Log level"
),
AP_INIT_NO_ARGS
(
"TequilaNoSSL"
,
cmd_nossl
,
NULL
,
RSRC_CONF
,
"No SSL support"
),
AP_INIT_NO_ARGS
(
"TequilaHasSSL"
,
cmd_usessl
,
NULL
,
RSRC_CONF
,
"SSL support"
),
AP_INIT_NO_ARGS
(
"TequilaUseSSL"
,
cmd_usessl
,
NULL
,
RSRC_CONF
,
"SSL support"
),
AP_INIT_TAKE1
(
"TequilaCAFile"
,
cmd_cafile
,
NULL
,
RSRC_CONF
,
"CA file"
),
AP_INIT_NO_ARGS
(
"TequilaCheckServerName"
,
cmd_checkservername
,
NULL
,
RSRC_CONF
,
"Check Server Name"
),
{
NULL
}
};
module
AP_MODULE_DECLARE_DATA
tequila_module
=
{
STANDARD20_MODULE_STUFF
,
create_perdir_config
,
/* create per-dir config structures */
merge_perdir_config
,
/* merge per-dir config structures */
create_global_config
,
/* create per-server config structures */
merge_global_config
,
/* merge per-server config structures */
command_table
,
/* table of config file commands */
register_hooks
/* register hooks */
};
static
void
register_hooks
(
AP_POOL
*
p
)
{
ap_hook_post_config
(
post_config
,
NULL
,
NULL
,
APR_HOOK_MIDDLE
);
ap_hook_header_parser
(
check_access
,
NULL
,
NULL
,
APR_HOOK_MIDDLE
);
ap_hook_translate_name
(
translate
,
NULL
,
NULL
,
APR_HOOK_FIRST
);
ap_hook_fixups
(
setenvvars
,
NULL
,
NULL
,
APR_HOOK_MIDDLE
);
}
APR_DECLARE_OPTIONAL_FN
(
int
,
ssl_is_https
,
(
conn_rec
*
));
static
APR_OPTIONAL_FN_TYPE
(
ssl_is_https
)
*
url_is_https
=
NULL
;
#else
/* APACHE2 */
static
const
command_rec
tequila_cmds
[]
=
{
{
"TequilaRewrite"
,
cmd_rewrite
,
NULL
,
OR_FILEINFO
,
TAKE1
,
"Rewrite"
},
{
"TequilaAllowIf"
,
cmd_allowif
,
NULL
,
OR_AUTHCFG
,
RAW_ARGS
,
"Access condition"
},
{
"TequilaRequest"
,
cmd_request
,
NULL
,
OR_AUTHCFG
,
RAW_ARGS
,
"Request"
},
{
"TequilaAllowNet"
,
cmd_allownet
,
NULL
,
OR_AUTHCFG
,
RAW_ARGS
,
"Allowed Net."
},
{
"TequilaAllows"
,
cmd_allows
,
NULL
,
OR_AUTHCFG
,
RAW_ARGS
,
"Allows attribute"
},
{
"TequilaService"
,
cmd_service
,
NULL
,
OR_AUTHCFG
,
TAKE1
,
"Service name"
},
{
"TequilaResource"
,
cmd_resource
,
NULL
,
OR_AUTHCFG
,
TAKE1
,
"Tequila resource"
},
{
"TequilaKeyFile"
,
cmd_sslkeyfile
,
NULL
,
OR_AUTHCFG
,
TAKE1
,
"SSL Key file"
},
{
"TequilaCertFile"
,
cmd_sslcertfile
,
NULL
,
OR_AUTHCFG
,
TAKE1
,
"SSL Cert file"
},
{
"TequilaServer"
,
cmd_server
,
NULL
,
RSRC_CONF
,
TAKE1
,
"Local Tequila server"
},
{
"TequilaSessionDir"
,
cmd_sessdir
,
NULL
,
RSRC_CONF
,
TAKE1
,
"Session directory."
},
{
"TequilaSessionMax"
,
cmd_sessmax
,
NULL
,
RSRC_CONF
,
TAKE1
,
"Session duration."
},
{
"TequilaLog"
,
cmd_log
,
NULL
,
RSRC_CONF
,
TAKE1
,
"Filename of the logfile"
},
{
"TequilaLogLevel"
,
cmd_loglevel
,
NULL
,
RSRC_CONF
,
TAKE1
,
"Log level"
},
{
"TequilaNoSSL"
,
cmd_nossl
,
NULL
,
RSRC_CONF
,
NO_ARGS
,
"No SSL support"
},
{
"TequilaHasSSL"
,
cmd_usessl
,
NULL
,
RSRC_CONF
,
NO_ARGS
,
"SSL support"
},
{
"TequilaUseSSL"
,
cmd_usessl
,
NULL
,
RSRC_CONF
,
NO_ARGS
,
"SSL support"
},
{
"TequilaCAFile"
,
cmd_cafile
,
NULL
,
RSRC_CONF
,
TAKE1
,
"CA file"
},
{
"TequilaCheckServerName"
,
cmd_checkservername
,
NULL
,
RSRC_CONF
,
NO_ARGS
,
"Check Server Name"
},
{
NULL
}
};
module
MODULE_VAR_EXPORT
tequila_module
=
{
STANDARD_MODULE_STUFF
,
init_module
,
/* initializer */
create_perdir_config
,
/* create per-directory config structure */
merge_perdir_config
,
/* merge per-directory config structures */
create_global_config
,
/* create per-server config structure */
merge_global_config
,
/* server config merger */
tequila_cmds
,
/* table of config file commands */
NULL
,
/* [#8] MIME-typed-dispatched handlers */
translate
,
/* [#1] URI to filename translation */
NULL
,
/* [#4] validate user id from request */
NULL
,
/* [#5] check if the user is ok _here_ */
NULL
,
/* [#3] check access by host address */
NULL
,
/* [#6] determine MIME type */
setenvvars
,
/* [#7] pre-run fixups */
NULL
,
/* [#9] logger */
check_access
,
/* [#2] header parser */
NULL
,
/* child_init */
NULL
,
/* child_exit */
NULL
/* [#0] post read-request */
};
#endif
/* APACHE2 */
static
int
keyfromcookie
=
0
;
static
char
*
defaultsessdir
=
"/var/www/Tequila/Sessions"
;
static
char
*
defaultteqserver
=
"tequila"
;
static
int
defaultsessmax
=
12
*
3600
;
#ifdef USESSL
typedef
struct
{
SSL_CTX
*
ctx
;
BIO
*
bio
;
}
SSLenv
;
static
SSLenv
*
opensslsocket
(
request_rec
*
r
,
char
*
host
,
int
port
);
static
void
closesslsocket
(
SSLenv
*
sslenv
);
static
int
checkcertificate
(
request_rec
*
r
,
X509
*
cert
,
char
*
host
);
#endif
static
int
translate
(
request_rec
*
r
)
{
tequila_perdir_conf
*
dconf
;
char
*
left
;
teqlog
(
r
,
99
,
"translate: uri = %s, filename = %s"
,
r
->
uri
,
r
->
filename
);
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
!
dconf
||
!
dconf
->
path
||
!
dconf
->
rewrite
)
return
DECLINED
;
left
=
skip_match
(
r
->
uri
,
dconf
->
path
);
if
(
!
strncmp
(
dconf
->
rewrite
,
"http:"
,
5
)
||
!
strncmp
(
dconf
->
rewrite
,
"https:"
,
6
))
{
r
->
proxyreq
=
PROXYREQ
;
r
->
handler
=
"proxy-server"
;
r
->
filename
=
AP_STRCAT
(
r
->
pool
,
"proxy:"
,
dconf
->
rewrite
,
left
,
NULL
);
if
(
r
->
path_info
!=
NULL
&&
r
->
uri
==
r
->
unparsed_uri
)
{
r
->
filename
=
AP_STRCAT
(
r
->
pool
,
r
->
filename
,
r
->
path_info
,
NULL
);
}
if
(
r
->
args
!=
NULL
)
{
r
->
filename
=
AP_STRCAT
(
r
->
pool
,
r
->
filename
,
"?"
,
r
->
args
,
NULL
);
}
}
else
{
r
->
filename
=
AP_STRCAT
(
r
->
pool
,
dconf
->
rewrite
,
left
,
NULL
);
}
/*
if (r->path_info != NULL && r->uri == r->unparsed_uri) {
r->filename = AP_STRCAT (r->pool, r->filename, r->path_info, NULL);
}
if (r->args != NULL) {
r->filename = AP_STRCAT (r->pool, r->filename, "?", r->args, NULL);
}
*/
if
(
r
->
main
&&
r
->
main
->
args
)
{
r
->
args
=
AP_STRDUP
(
r
->
pool
,
r
->
main
->
args
);
}
teqlog
(
r
,
2
,
"translate: url %s rewritten to %s"
,
r
->
uri
,
r
->
filename
);
return
OK
;
}
static
int
check_access
(
request_rec
*
r
)
{
tequila_perdir_conf
*
dconf
;
char
*
key
;
int
status
;
teqlog
(
r
,
99
,
"check_access: uri = %s, filename = %s"
,
r
->
uri
,
r
->
filename
);
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
dconf
==
NULL
||
(
dconf
->
allowif
==
NULL
&&
dconf
->
allownet
==
NULL
))
return
DECLINED
;
if
(
dconf
->
allownet
&&
check_net
(
r
))
return
OK
;
key
=
getkey
(
r
);
if
(
key
)
{
Session
*
session
;
teqlog
(
r
,
5
,
"check_access: key = %s"
,
key
);
session
=
readsession
(
r
,
key
);
if
(
session
)
{
dconf
->
session
=
session
;
if
(
!
r
->
main
&&
!
keyfromcookie
)
set_cookie
(
r
,
key
);
teqlog
(
r
,
2
,
"check_access: session OK"
);
return
OK
;
}
teqlog
(
r
,
3
,
"check_access: readsession failed"
);
session
=
fetchattributes
(
r
,
key
);
if
(
session
)
{
dconf
->
session
=
session
;
if
(
!
r
->
main
&&
!
keyfromcookie
)
set_cookie
(
r
,
key
);
teqlog
(
r
,
2
,
"check_access: fetchattributes OK"
);
return
OK
;
}
teqlog
(
r
,
3
,
"check_access: fetchattributes failed"
);
// return HTTP_NOT_MODIFIED;
}
status
=
createserverrequest
(
r
);
teqlog
(
r
,
2
,
"check_access: redirect to %s
\n
"
,
r
->
filename
);
return
status
;
}
static
int
check_net
(
request_rec
*
r
)
{
conn_rec
*
connection
;
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
!
dconf
||
!
dconf
->
allownet
||
!
dconf
->
allownet
->
nelts
)
return
0
;
connection
=
r
->
connection
;
if
(
connection
&&
connection
->
remote_ip
)
{
int
i
;
char
*
ip
=
connection
->
remote_ip
;
char
**
netp
=
(
char
**
)
dconf
->
allownet
->
elts
;
for
(
i
=
0
;
i
<
dconf
->
allownet
->
nelts
;
i
++
)
{
char
*
net
=
netp
[
i
];
teqlog
(
r
,
4
,
"check_net: comparing %s to %s"
,
ip
,
net
);
if
(
strstr
(
ip
,
net
)
==
ip
)
{
char
*
left
=
skip_match
(
r
->
uri
,
dconf
->
path
);
teqlog
(
r
,
4
,
"check_net: %s matches %s, access allowed.
\n
"
,
ip
,
net
);
teqlog
(
r
,
2
,
"check_net: Acces authorised for ip address %s (%s)"
,
ip
,
net
);
return
1
;
}
teqlog
(
r
,
2
,
"check_net: %s doesn't match %s"
,
ip
,
net
);
}
}
return
0
;
}
static
char
*
getRequest
(
request_rec
*
r
)
{
int
i
;
char
**
reqp
,
*
request
;
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
!
dconf
||
!
dconf
->
request
||
!
dconf
->
request
->
nelts
)
return
NULL
;
reqp
=
(
char
**
)
dconf
->
request
->
elts
;
request
=
AP_STRDUP
(
r
->
pool
,
reqp
[
0
]);
for
(
i
=
1
;
i
<
dconf
->
request
->
nelts
;
i
++
)
{
request
=
AP_STRCAT
(
r
->
pool
,
request
,
"+"
,
reqp
[
i
],
NULL
);
}
teqlog
(
r
,
1
,
"getRequest: request = %s"
,
request
);
return
request
;
}
static
char
*
getFilter
(
request_rec
*
r
)
{
tequila_perdir_conf
*
dconf
;
int
i
;
char
*
strfilt
=
NULL
;
Filter
*
filter
;
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
dconf
==
NULL
||
dconf
->
allowif
==
NULL
)
return
NULL
;
filter
=
(
Filter
*
)
dconf
->
allowif
->
elts
;
for
(
i
=
0
;
i
<
dconf
->
allowif
->
nelts
;
i
++
)
{
int
first
;
Filter
*
filt
=
(
Filter
*
)
(
filter
+
i
);
if
(
strfilt
!=
NULL
)
strfilt
=
AP_STRCAT
(
r
->
pool
,
strfilt
,
"|"
,
NULL
);
first
=
1
;
while
(
filt
)
{
if
(
!
first
)
strfilt
=
AP_STRCAT
(
r
->
pool
,
strfilt
,
"&"
,
NULL
);
else
first
=
0
;
if
(
strfilt
!=
NULL
)
{
strfilt
=
AP_STRCAT
(
r
->
pool
,
strfilt
,
filt
->
nam
,
"="
,
filt
->
val
,
NULL
);
}
else
{
strfilt
=
AP_STRCAT
(
r
->
pool
,
filt
->
nam
,
"="
,
filt
->
val
,
NULL
);
}
filt
=
filt
->
next
;
}
}
return
strfilt
;
}
static
char
*
getAllows
(
request_rec
*
r
)
{
tequila_perdir_conf
*
dconf
;
int
i
;
char
*
strallows
=
NULL
;
Filter
*
allows
;
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
dconf
==
NULL
||
dconf
->
allows
==
NULL
)
return
NULL
;
allows
=
(
Filter
*
)
dconf
->
allows
->
elts
;
for
(
i
=
0
;
i
<
dconf
->
allows
->
nelts
;
i
++
)
{
int
first
;
Filter
*
allo
=
(
Filter
*
)
(
allows
+
i
);
if
(
strallows
!=
NULL
)
strallows
=
AP_STRCAT
(
r
->
pool
,
strallows
,
"%7c"
,
NULL
);
first
=
1
;
while
(
allo
)
{
if
(
!
first
)
strallows
=
AP_STRCAT
(
r
->
pool
,
strallows
,
"%26"
,
NULL
);
else
first
=
0
;
if
(
strallows
!=
NULL
)
{
strallows
=
AP_STRCAT
(
r
->
pool
,
strallows
,
allo
->
nam
,
"%3d"
,
allo
->
val
,
NULL
);
}
else
{
strallows
=
AP_STRCAT
(
r
->
pool
,
allo
->
nam
,
"%3d"
,
allo
->
val
,
NULL
);
}
allo
=
allo
->
next
;
}
}
return
strallows
;
}
static
Session
*
readsession
(
request_rec
*
r
,
char
*
key
)
{
tequila_global_conf
*
gconf
;
tequila_perdir_conf
*
dconf
;
void
*
sconf
=
r
->
server
->
module_config
;
AP_PERM_T
flags
=
(
AP_READ
);
AP_MODE_T
mode
=
(
AP_UREAD
);
AP_FILE_T
fp
;
AP_STATUS
rc
;
AP_SIZE_T
nbytes
;
unsigned
int
i
;
struct
stat
buf
;
time_t
now
,
mtime
;
char
buffer
[
1024
];
char
*
sessionstring
=
NULL
,
*
s
;
char
*
requiredfilter
;
char
*
sessdir
;
time_t
sessmax
;
char
*
fname
;
Session
*
session
;
teqlog
(
r
,
3
,
"readsession: key = %s"
,
key
);
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
sconf
,
&
tequila_module
);
sessdir
=
gconf
->
sessdir
;
if
(
sessdir
==
NULL
)
sessdir
=
defaultsessdir
;
sessmax
=
gconf
->
sessmax
;
if
(
sessmax
==
0
)
sessmax
=
defaultsessmax
;
fname
=
AP_STRCAT
(
r
->
pool
,
sessdir
,
"/"
,
key
,
NULL
);
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
((
dconf
==
NULL
)
||
(
dconf
->
allowif
==
NULL
))
{
teqlog
(
r
,
2
,
"readsession: internal error."
);
return
NULL
;
}
if
(
stat
(
fname
,
&
buf
)
==
-
1
)
{
/* does not exist */
teqlog
(
r
,
2
,
"readsession: could not open session file %s"
,
fname
);
return
NULL
;
}
now
=
time
(
NULL
);
mtime
=
buf
.
st_mtime
;
if
(
now
>
mtime
+
sessmax
)
{
unlink
(
fname
);
teqlog
(
r
,
2
,
"readsession: session %s expired."
,
key
);
return
NULL
;
}
if
(
utime
(
fname
,
NULL
)
==
-
1
)
{
teqlog
(
r
,
2
,
"readsession: cannot reset usage time on session %s."
,
key
);
return
NULL
;
}
sessionstring
=
""
;
#ifdef APACHE2
if
((
rc
=
AP_FILEOPEN
(
&
fp
,
fname
,
flags
,
mode
,
r
->
pool
))
!=
AP_SUCCESS
)
{
teqlog
(
r
,
2
,
"readsession: cannot open session file : %s"
,
fname
);
return
NULL
;
}
nbytes
=
1023
;
while
(
AP_FILEREAD
(
fp
,
buffer
,
&
nbytes
)
==
AP_SUCCESS
)
{
buffer
[
nbytes
]
=
'\0'
;
sessionstring
=
AP_STRCAT
(
r
->
pool
,
sessionstring
,
buffer
,
NULL
);
nbytes
=
1023
;
}
AP_FILECLOSE
(
fp
);
#else
if
((
fp
=
AP_FILEOPEN
(
r
->
pool
,
fname
,
flags
,
mode
))
<
0
)
{
teqlog
(
r
,
2
,
"readsession: cannot open session file : %s"
,
fname
);
return
NULL
;
}
while
(
nbytes
=
AP_FILEREAD
(
fp
,
buffer
,
1023
))
{
if
(
nbytes
<
0
)
break
;
buffer
[
nbytes
]
=
'\0'
;
sessionstring
=
AP_STRCAT
(
r
->
pool
,
sessionstring
,
buffer
,
NULL
);
}
ap_pclosef
(
r
->
pool
,
fp
);
#endif
session
=
(
Session
*
)
AP_ALLOC
(
r
->
pool
,
sizeof
(
Session
));
session
->
attrs
=
AP_TABLE_MAKE
(
r
->
pool
,
16
);
s
=
sessionstring
;
while
(
*
s
)
{
char
*
attr
,
*
value
,
u
;
char
*
t
=
s
;
while
(
*
t
&&
(
*
t
!=
'='
))
t
++
;
if
(
!*
t
)
{
teqlog
(
r
,
1
,
"readsession: malformed session file : %s"
,
s
);
*
s
=
'\0'
;
break
;
}
*
t
=
'\0'
;
attr
=
AP_STRDUP
(
r
->
pool
,
s
);
s
=
++
t
;
while
(
*
t
&&
(
*
t
!=
'\n'
)
&&
(
*
t
!=
'\r'
))
t
++
;
u
=
*
t
;
*
t
=
'\0'
;
value
=
AP_STRDUP
(
r
->
pool
,
s
);
*
t
=
u
;
while
((
*
t
==
'\n'
)
||
(
*
t
==
'\r'
))
t
++
;
s
=
t
;
if
(
!
strcmp
(
attr
,
"org"
))
{
session
->
org
=
value
;
continue
;
}
if
(
!
strcmp
(
attr
,
"user"
))
{
session
->
user
=
value
;
continue
;
}
if
(
!
strcmp
(
attr
,
"host"
))
{
session
->
host
=
value
;
continue
;
}
if
(
!
strcmp
(
attr
,
"hash"
))
{
session
->
hash
=
value
;
continue
;
}
if
(
!
strcmp
(
attr
,
"path"
))
{
session
->
path
=
value
;
continue
;
}
if
(
!
strcmp
(
attr
,
"require"
))
{
session
->
filter
=
value
;
continue
;
}
AP_TABLESET
(
session
->
attrs
,
attr
,
value
);
}
if
(
!
session
->
org
)
{
teqlog
(
r
,
2
,
"readsession: no org found"
);
return
NULL
;
}
if
(
!
session
->
user
)
{
teqlog
(
r
,
2
,
"readsession: no user found"
);
return
NULL
;
}
if
(
!
session
->
host
)
{
teqlog
(
r
,
2
,
"readsession: no host found"
);
return
NULL
;
}
if
(
!
session
->
hash
)
{
teqlog
(
r
,
2
,
"readsession: no hash found"
);
return
NULL
;
}
if
(
!
session
->
path
)
{
teqlog
(
r
,
2
,
"readsession: no path found"
);
return
NULL
;
}
requiredfilter
=
getFilter
(
r
);
if
(
requiredfilter
)
{
if
(
session
->
filter
)
{
teqlog
(
r
,
3
,
"readsession: requiredfilter = %s, session->filter = %s."
,
requiredfilter
,
session
->
filter
);
}
else
{
teqlog
(
r
,
3
,
"readsession: requiredfilter = %s, session->filter = (null)."
,
requiredfilter
);
}
if
(
!
session
->
filter
||
strcmp
(
requiredfilter
,
session
->
filter
))
{
teqlog
(
r
,
2
,
"readsession: requiredfilter doesn't match session->filter."
);
return
NULL
;
}
}
return
(
session
);
}
static
int
writesession
(
request_rec
*
r
,
char
*
sessdir
,
Session
*
session
)
{
char
*
pathhash
,
*
fname
;
int
i
;
AP_FILE_T
fp
;
AP_STATUS
rc
;
AP_SIZE_T
nbytes
;
AP_MODE_T
flags
=
(
AP_WRITE
|
AP_CREATE
);
AP_PERM_T
mode
=
(
AP_UREAD
|
AP_UWRITE
);
const
AP_ARRAY_HEADER_T
*
hdrs_attrs
;
const
AP_TABLE_ENTRY_T
*
hdrs
;
if
(
sessdir
==
NULL
)
sessdir
=
defaultsessdir
;
pathhash
=
AP_SPRINTF
(
r
->
pool
,
"%u"
,
hash
(
session
->
path
));
fname
=
AP_STRCAT
(
r
->
pool
,
sessdir
,
"/"
,
session
->
key
,
NULL
);
#ifdef APACHE2
if
((
rc
=
AP_FILEOPEN
(
&
fp
,
fname
,
flags
,
mode
,
r
->
pool
))
!=
AP_SUCCESS
)
{
#else
if
((
fp
=
AP_FILEOPEN
(
r
->
pool
,
fname
,
flags
,
mode
))
<
0
)
{
#endif
teqlog
(
r
,
2
,
"writesession: could not create session file %s, status = %d"
,
fname
,
rc
);
r
->
status
=
450
;
r
->
status_line
=
AP_SPRINTF
(
r
->
pool
,
"450 Unable to create session : file = %s"
,
fname
);
return
0
;
}
writeline
(
fp
,
AP_STRCAT
(
r
->
pool
,
"org="
,
session
->
org
,
NULL
));
writeline
(
fp
,
AP_STRCAT
(
r
->
pool
,
"user="
,
session
->
user
,
NULL
));
writeline
(
fp
,
AP_STRCAT
(
r
->
pool
,
"host="
,
session
->
host
,
NULL
));
writeline
(
fp
,
AP_STRCAT
(
r
->
pool
,
"hash="
,
pathhash
,
NULL
));
writeline
(
fp
,
AP_STRCAT
(
r
->
pool
,
"path="
,
session
->
path
,
NULL
));
writeline
(
fp
,
AP_STRCAT
(
r
->
pool
,
"require="
,
session
->
filter
,
NULL
));
hdrs_attrs
=
AP_TABLE_ELTS
(
session
->
attrs
);
hdrs
=
(
const
AP_TABLE_ENTRY_T
*
)
hdrs_attrs
->
elts
;
for
(
i
=
0
;
i
<
hdrs_attrs
->
nelts
;
i
++
)
{
if
(
!
hdrs
[
i
].
key
)
continue
;
writeline
(
fp
,
AP_STRCAT
(
r
->
pool
,
hdrs
[
i
].
key
,
"="
,
hdrs
[
i
].
val
,
NULL
));
}
#ifdef APACHE2
AP_FILECLOSE
(
fp
);
#else
ap_pclosef
(
r
->
pool
,
fp
);
#endif
teqlog
(
r
,
2
,
"writesession: session %s created"
,
session
->
key
);
}
static
void
writeline
(
AP_FILE_T
fp
,
char
*
string
)
{
AP_SIZE_T
nbytes
=
strlen
(
string
);
#ifdef APACHE2
AP_FILEWRITE
(
fp
,
string
,
&
nbytes
);
nbytes
=
1
;
AP_FILEWRITE
(
fp
,
"
\n
"
,
&
nbytes
);
#else
write
(
fp
,
string
,
nbytes
);
write
(
fp
,
"
\n
"
,
1
);
#endif
}
static
void
substsepar
(
char
*
string
,
char
oldsepar
,
char
newsepar
)
{
char
*
s
=
string
;
while
(
*
s
)
{
if
(
*
s
==
oldsepar
)
*
s
=
newsepar
;
s
++
;
}
}
static
const
char
*
cmd_rewrite
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
path
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
dconf
->
rewrite
=
AP_STRDUP
(
cmd
->
pool
,
path
);
return
NULL
;
}
static
const
char
*
cmd_allowif
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
cond
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
Filter
*
filter
,
*
new
;
filter
=
parsefilter
(
cmd
,
cond
);
if
(
filter
==
NULL
)
return
NULL
;
new
=
AP_ARRAYPUSH
(
dconf
->
allowif
);
new
->
nam
=
filter
->
nam
;
new
->
val
=
filter
->
val
;
new
->
next
=
filter
->
next
;
return
NULL
;
}
static
const
char
*
cmd_allownet
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
net
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
const
char
**
netp
;
if
(
!
net
)
return
NULL
;
netp
=
(
const
char
**
)
AP_ARRAYPUSH
(
dconf
->
allownet
);
*
netp
=
AP_STRDUP
(
cmd
->
pool
,
net
);
return
NULL
;
}
static
const
char
*
cmd_request
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
request
)
{
char
*
r
;
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
const
char
**
reqp
;
if
(
!
request
)
return
NULL
;
r
=
(
char
*
)
request
;
while
((
*
r
==
' '
)
||
(
*
r
==
','
)
||
(
*
r
==
'\r'
)
||
(
*
r
==
'\n'
))
r
++
;
while
(
*
r
)
{
char
*
s
=
r
;
char
t
;
while
(
*
s
&&
(
*
s
!=
' '
)
&&
(
*
s
!=
','
)
&&
(
*
s
!=
'\r'
)
&&
(
*
s
!=
'\n'
))
s
++
;
t
=
*
s
;
*
s
=
'\0'
;
reqp
=
(
const
char
**
)
AP_ARRAYPUSH
(
dconf
->
request
);
*
reqp
=
AP_STRDUP
(
cmd
->
pool
,
r
);
*
s
=
t
;
while
((
*
s
==
' '
)
||
(
*
s
==
','
)
||
(
*
s
==
'\r'
)
||
(
*
s
==
'\n'
))
s
++
;
r
=
s
;
}
return
NULL
;
}
static
const
char
*
cmd_service
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
servname
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
dconf
->
servname
=
AP_STRDUP
(
cmd
->
pool
,
servname
);
return
NULL
;
}
static
const
char
*
cmd_allows
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
cond
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
Filter
*
filter
,
*
new
;
filter
=
parsefilter
(
cmd
,
cond
);
if
(
filter
==
NULL
)
return
NULL
;
new
=
AP_ARRAYPUSH
(
dconf
->
allows
);
new
->
nam
=
filter
->
nam
;
new
->
val
=
filter
->
val
;
new
->
next
=
filter
->
next
;
return
NULL
;
}
static
const
char
*
cmd_server
(
cmd_parms
*
cmd
,
void
*
dummy
,
cmd_arg
*
server
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
teqserver
=
AP_STRDUP
(
cmd
->
pool
,
server
);
return
NULL
;
}
static
const
char
*
cmd_resource
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
resname
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
dconf
->
resource
=
AP_STRDUP
(
cmd
->
pool
,
resname
);
return
NULL
;
}
static
const
char
*
cmd_sslkeyfile
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
keyfile
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
dconf
->
keyfile
=
AP_STRDUP
(
cmd
->
pool
,
keyfile
);
return
NULL
;
}
static
const
char
*
cmd_sslcertfile
(
cmd_parms
*
cmd
,
cmd_conf
*
vconf
,
cmd_arg
*
certfile
)
{
tequila_perdir_conf
*
dconf
=
(
tequila_perdir_conf
*
)
vconf
;
dconf
->
certfile
=
AP_STRDUP
(
cmd
->
pool
,
certfile
);
return
NULL
;
}
static
const
char
*
cmd_sessdir
(
cmd_parms
*
cmd
,
void
*
dummy
,
cmd_arg
*
sessdir
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
sessdir
=
AP_STRDUP
(
cmd
->
pool
,
sessdir
);
return
NULL
;
}
static
const
char
*
cmd_sessmax
(
cmd_parms
*
cmd
,
void
*
dummy
,
cmd_arg
*
sessmax
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
sessmax
=
atoi
(
sessmax
);
return
NULL
;
}
static
const
char
*
cmd_log
(
cmd_parms
*
cmd
,
void
*
dummy
,
cmd_arg
*
logfile
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
logfile
=
AP_STRDUP
(
cmd
->
pool
,
logfile
);
return
NULL
;
}
static
const
char
*
cmd_loglevel
(
cmd_parms
*
cmd
,
void
*
dummy
,
cmd_arg
*
loglevel
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
loglevel
=
atoi
(
loglevel
);
return
NULL
;
}
static
const
char
*
cmd_nossl
(
cmd_parms
*
cmd
,
void
*
dummy
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
usessl
=
0
;
return
NULL
;
}
static
const
char
*
cmd_usessl
(
cmd_parms
*
cmd
,
void
*
dummy
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
usessl
=
1
;
return
NULL
;
}
static
const
char
*
cmd_cafile
(
cmd_parms
*
cmd
,
void
*
dummy
,
cmd_arg
*
cafile
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
cafile
=
AP_STRDUP
(
cmd
->
pool
,
cafile
);
return
NULL
;
}
static
const
char
*
cmd_checkservername
(
cmd_parms
*
cmd
,
void
*
dummy
)
{
server_rec
*
s
=
cmd
->
server
;
tequila_global_conf
*
gconf
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
gconf
->
checkservername
=
1
;
return
NULL
;
}
static
Filter
*
parsefilter
(
cmd_parms
*
cmd
,
const
char
*
str
)
{
char
*
cstr
=
AP_STRDUP
(
cmd
->
pool
,
str
);
char
*
s
=
cstr
;
Filter
*
filter
=
NULL
,
*
filt
;
while
(
*
s
)
{
char
*
n
,
*
v
;
n
=
s
;
while
(
*
s
&&
*
s
!=
'='
)
s
++
;
if
(
!*
s
)
break
;
*
s
=
'\0'
;
s
++
;
v
=
s
;
while
(
*
s
&&
*
s
!=
'&'
)
s
++
;
if
(
*
s
)
{
*
s
=
'\0'
;
s
++
;
}
filt
=
(
Filter
*
)
AP_ALLOC
(
cmd
->
pool
,
sizeof
(
Filter
));
filt
->
nam
=
AP_STRDUP
(
cmd
->
pool
,
n
);
filt
->
val
=
AP_STRDUP
(
cmd
->
pool
,
v
);
filt
->
next
=
filter
;
filter
=
filt
;
}
return
filt
;
}
static
void
printfilter
(
request_rec
*
r
,
Filter
*
filter
)
{
if
(
r
==
NULL
)
{
fprintf
(
stderr
,
"printfilter: filter = "
);
}
else
{
teqlog
(
r
,
3
,
"printfilter: filter = "
);
}
while
(
filter
)
{
if
(
r
==
NULL
)
{
fprintf
(
stderr
,
" (%s=%s) "
,
filter
->
nam
,
filter
->
val
);
}
else
{
teqlog
(
r
,
3
,
" (%s=%s) "
,
filter
->
nam
,
filter
->
val
);
}
filter
=
filter
->
next
;
}
if
(
r
==
NULL
)
fprintf
(
stderr
,
"
\n
"
);
}
static
int
uri_match
(
const
char
*
uri1
,
const
char
*
uri2
)
{
const
char
*
end_uri2
=
uri2
+
strlen
(
uri2
);
const
char
*
u1
=
uri1
,
*
u2
=
uri2
;
while
(
u2
<
end_uri2
)
{
if
(
*
u2
==
'/'
)
{
if
(
*
u1
!=
'/'
)
return
0
;
while
(
*
u2
==
'/'
)
++
u2
;
while
(
*
u1
==
'/'
)
++
u1
;
}
else
{
if
(
*
u1
++
!=
*
u2
++
)
return
0
;
}
}
if
(
u2
[
-
1
]
!=
'/'
&&
*
u1
!=
'\0'
&&
*
u1
!=
'/'
)
return
0
;
return
u1
-
uri1
;
}
static
char
*
skip_match
(
char
*
uri
,
char
*
prefix
)
{
char
*
x
=
prefix
+
strlen
(
prefix
);
char
*
p
=
prefix
,
*
urip
=
uri
;
while
(
p
<
x
)
{
if
(
*
p
==
'/'
)
{
while
(
*
p
==
'/'
)
++
p
;
while
(
*
urip
==
'/'
)
++
urip
;
}
else
{
*
urip
++
;
*
p
++
;
}
}
return
urip
;
}
static
void
*
create_perdir_config
(
AP_POOL
*
p
,
char
*
path
)
{
tequila_perdir_conf
*
dconf
;
dconf
=
(
tequila_perdir_conf
*
)
AP_ALLOC
(
p
,
sizeof
(
tequila_perdir_conf
));
if
(
path
==
NULL
)
return
NULL
;
dconf
->
path
=
AP_STRDUP
(
p
,
path
);
dconf
->
rewrite
=
NULL
;
dconf
->
resource
=
NULL
;
dconf
->
keyfile
=
NULL
;
dconf
->
certfile
=
NULL
;
dconf
->
servname
=
NULL
;
dconf
->
session
=
NULL
;
dconf
->
allowif
=
AP_ARRAYMAKE
(
p
,
2
,
sizeof
(
Filter
));
dconf
->
allownet
=
AP_ARRAYMAKE
(
p
,
2
,
sizeof
(
char
*
));
dconf
->
allows
=
AP_ARRAYMAKE
(
p
,
2
,
sizeof
(
Filter
));
dconf
->
request
=
AP_ARRAYMAKE
(
p
,
2
,
sizeof
(
char
*
));
return
(
void
*
)
dconf
;
}
static
void
*
merge_perdir_config
(
AP_POOL
*
p
,
void
*
base_conf
,
void
*
over_conf
)
{
tequila_perdir_conf
*
mergeconf
=
AP_ALLOC
(
p
,
sizeof
(
tequila_perdir_conf
));
tequila_perdir_conf
*
baseconf
=
(
tequila_perdir_conf
*
)
base_conf
;
tequila_perdir_conf
*
overconf
=
(
tequila_perdir_conf
*
)
over_conf
;
mergeconf
->
path
=
overconf
->
path
;
mergeconf
->
rewrite
=
overconf
->
rewrite
;
mergeconf
->
resource
=
overconf
->
resource
;
mergeconf
->
keyfile
=
overconf
->
keyfile
;
mergeconf
->
certfile
=
overconf
->
certfile
;
mergeconf
->
servname
=
overconf
->
servname
;
mergeconf
->
session
=
overconf
->
session
;
mergeconf
->
allowif
=
overconf
->
allowif
;
mergeconf
->
allownet
=
overconf
->
allownet
;
mergeconf
->
allows
=
overconf
->
allows
;
mergeconf
->
request
=
overconf
->
request
;
return
(
void
*
)
mergeconf
;
}
static
void
*
create_global_config
(
AP_POOL
*
p
,
server_rec
*
s
)
{
tequila_global_conf
*
gconf
=
AP_ALLOC
(
p
,
sizeof
(
tequila_global_conf
));
gconf
->
logfile
=
NULL
;
gconf
->
teqserver
=
NULL
;
gconf
->
sessdir
=
NULL
;
gconf
->
sessmax
=
0
;
gconf
->
logfp
=
0
;
gconf
->
loglevel
=
-
1
;
gconf
->
usessl
=
1
;
gconf
->
cafile
=
NULL
;
gconf
->
checkservername
=
0
;
return
(
void
*
)
gconf
;
}
#define max(a,b) ((a > b) ? a : b)
static
void
*
merge_global_config
(
AP_POOL
*
p
,
void
*
base_conf
,
void
*
over_conf
)
{
tequila_global_conf
*
mergeconf
=
AP_ALLOC
(
p
,
sizeof
(
tequila_global_conf
));
tequila_global_conf
*
baseconf
=
(
tequila_global_conf
*
)
base_conf
;
tequila_global_conf
*
overconf
=
(
tequila_global_conf
*
)
over_conf
;
mergeconf
->
logfile
=
overconf
->
logfile
?
AP_STRDUP
(
p
,
overconf
->
logfile
)
:
AP_STRDUP
(
p
,
baseconf
->
logfile
);
mergeconf
->
teqserver
=
overconf
->
teqserver
?
AP_STRDUP
(
p
,
overconf
->
teqserver
)
:
AP_STRDUP
(
p
,
baseconf
->
teqserver
);
mergeconf
->
sessdir
=
overconf
->
sessdir
?
AP_STRDUP
(
p
,
overconf
->
sessdir
)
:
AP_STRDUP
(
p
,
baseconf
->
sessdir
);
mergeconf
->
cafile
=
overconf
->
cafile
?
AP_STRDUP
(
p
,
overconf
->
cafile
)
:
AP_STRDUP
(
p
,
baseconf
->
cafile
);
mergeconf
->
sessmax
=
overconf
->
sessmax
?
overconf
->
sessmax
:
baseconf
->
sessmax
;
mergeconf
->
logfp
=
0
;
if
(
overconf
->
loglevel
==
-
1
)
{
mergeconf
->
loglevel
=
baseconf
->
loglevel
;
}
else
{
mergeconf
->
loglevel
=
overconf
->
loglevel
;
}
mergeconf
->
usessl
=
baseconf
->
usessl
&&
overconf
->
usessl
;
mergeconf
->
checkservername
=
baseconf
->
checkservername
&&
overconf
->
checkservername
;
return
(
void
*
)
mergeconf
;
}
static
void
openteqlog
(
server_rec
*
s
,
AP_POOL
*
p
)
{
tequila_global_conf
*
gconf
;
char
*
fname
;
piped_log
*
pl
;
AP_STATUS
rc
;
AP_MODE_T
flags
=
(
AP_WRITE
|
AP_APPEND
|
AP_CREATE
);
AP_PERM_T
mode
=
(
AP_UREAD
|
AP_UWRITE
|
AP_GREAD
|
AP_WREAD
);
gconf
=
ap_get_module_config
(
s
->
module_config
,
&
tequila_module
);
if
(
gconf
->
logfile
==
NULL
)
return
;
if
(
*
(
gconf
->
logfile
)
==
'\0'
)
return
;
if
(
gconf
->
logfp
)
return
;
/* virtual log shared w/ main server */
if
(
*
gconf
->
logfile
==
'|'
)
{
if
((
pl
=
ap_open_piped_log
(
p
,
gconf
->
logfile
+
1
))
==
NULL
)
{
#ifdef APACHE2
ap_log_error
(
APLOG_MARK
,
APLOG_ERR
,
0
,
s
,
#else
ap_log_error
(
APLOG_MARK
,
APLOG_ERR
,
s
,
#endif
"mod_tequila: could not open reliable pipe "
"to TequilaLog filter %s"
,
gconf
->
logfile
+
1
);
exit
(
1
);
}
gconf
->
logfp
=
ap_piped_log_write_fd
(
pl
);
}
else
if
(
*
gconf
->
logfile
!=
'\0'
)
{
fname
=
ap_server_root_relative
(
p
,
gconf
->
logfile
);
#ifdef APACHE2
if
((
rc
=
AP_FILEOPEN
(
&
gconf
->
logfp
,
fname
,
flags
,
mode
,
p
))
!=
AP_SUCCESS
)
{
gconf
->
logfp
=
NULL
;
ap_log_error
(
APLOG_MARK
,
APLOG_ERR
,
0
,
s
,
#else
if
((
gconf
->
logfp
=
AP_FILEOPEN
(
p
,
fname
,
flags
,
mode
))
<
0
)
{
gconf
->
logfp
=
0
;
ap_log_error
(
APLOG_MARK
,
APLOG_ERR
,
s
,
#endif
"mod_tequila: could not open Tequila log file : %s, %s"
,
fname
,
gconf
->
logfile
);
exit
(
1
);
}
}
return
;
}
static
void
teqlog
(
request_rec
*
r
,
int
level
,
const
char
*
text
,
...)
{
tequila_global_conf
*
gconf
;
conn_rec
*
conn
=
r
->
connection
;
char
*
str1
;
char
str2
[
2048
];
char
str3
[
2100
];
va_list
ap
;
int
i
;
ssize_t
wsize
;
char
*
now
;
const
char
*
rhost
;
#ifdef APACHE2
AP_STATUS
rv
;
AP_SIZE_T
nbytes
;
#endif
va_start
(
ap
,
text
);
if
(
r
==
NULL
)
{
if
(
level
>
default_loglevel
)
return
;
AP_VSNPRINTF
(
str2
,
sizeof
(
str2
),
text
,
ap
);
wsize
=
write
(
2
,
str2
,
strlen
(
str2
));
return
;
}
gconf
=
ap_get_module_config
(
r
->
server
->
module_config
,
&
tequila_module
);
if
(
!
gconf
->
logfp
)
return
;
if
(
gconf
->
logfile
==
NULL
)
return
;
if
(
*
(
gconf
->
logfile
)
==
'\0'
)
return
;
if
(
gconf
->
loglevel
==
-
1
)
gconf
->
loglevel
=
default_loglevel
;
if
(
level
>
gconf
->
loglevel
)
return
;
#ifdef APACHE2
rhost
=
ap_get_remote_host
(
conn
,
r
->
server
->
module_config
,
REMOTE_NOLOOKUP
,
NULL
);
#else
rhost
=
ap_get_remote_host
(
conn
,
r
->
server
->
module_config
,
REMOTE_NOLOOKUP
);
#endif
if
(
rhost
==
NULL
)
rhost
=
"UNKNOWN-HOST"
;
str1
=
AP_STRCAT
(
r
->
pool
,
rhost
,
NULL
);
AP_VSNPRINTF
(
str2
,
sizeof
(
str2
),
text
,
ap
);
va_end
(
ap
);
now
=
current_logtime
(
r
);
AP_SNPRINTF
(
str3
,
sizeof
(
str3
),
"%s %s (%d) %s
\n
"
,
str1
,
now
,
level
,
str2
);
#ifdef APACHE2
rv
=
apr_global_mutex_lock
(
tequila_log_lock
);
if
(
rv
!=
AP_SUCCESS
)
{
ap_log_rerror
(
APLOG_MARK
,
APLOG_ERR
,
rv
,
r
,
"apr_global_mutex_lock (tequila_log_lock) failed"
);
}
nbytes
=
strlen
(
str3
);
apr_file_write
(
gconf
->
logfp
,
str3
,
&
nbytes
);
rv
=
apr_global_mutex_unlock
(
tequila_log_lock
);
if
(
rv
!=
AP_SUCCESS
)
{
ap_log_rerror
(
APLOG_MARK
,
APLOG_ERR
,
rv
,
r
,
"apr_global_mutex_unlock (tequila_log_lock) failed"
);
}
#else
fd_lock
(
r
,
gconf
->
logfp
);
write
(
gconf
->
logfp
,
str3
,
strlen
(
str3
));
fd_unlock
(
r
,
gconf
->
logfp
);
#endif
return
;
}
static
char
*
current_logtime
(
request_rec
*
r
)
{
int
timz
;
char
tstr
[
80
];
char
sign
;
#ifdef APACHE2
apr_time_exp_t
xt
;
AP_SIZE_T
rv
;
ap_explode_recent_localtime
(
&
xt
,
r
->
request_time
);
timz
=
xt
.
tm_gmtoff
;
sign
=
(
timz
<
0
?
'-'
:
'+'
);
if
(
timz
<
0
)
timz
=
-
timz
;
timz
=
timz
/
60
;
apr_strftime
(
tstr
,
&
rv
,
80
,
"[%d/%b/%Y:%H:%M:%S "
,
&
xt
);
#else
struct
tm
*
t
;
t
=
ap_get_gmtoff
(
&
timz
);
sign
=
(
timz
<
0
?
'-'
:
'+'
);
if
(
timz
<
0
)
timz
=
-
timz
;
timz
=
timz
/
60
;
strftime
(
tstr
,
80
,
"[%d/%b/%Y:%H:%M:%S "
,
t
);
#endif
AP_SNPRINTF
(
tstr
+
strlen
(
tstr
),
80
-
strlen
(
tstr
),
"%c%.2d%.2d]"
,
sign
,
timz
/
60
,
timz
%
60
);
return
AP_STRDUP
(
r
->
pool
,
tstr
);
}
#ifdef APACHE2
static
int
post_config
(
AP_POOL
*
p
,
AP_POOL
*
plog
,
AP_POOL
*
ptemp
,
server_rec
*
s
)
{
AP_STATUS
rv
;
void
*
data
;
proxy_available
=
(
ap_find_linked_module
(
"mod_proxy.c"
)
!=
NULL
);
if
((
rv
=
apr_global_mutex_create
(
&
tequila_log_lock
,
NULL
,
APR_LOCK_DEFAULT
,
p
))
!=
AP_SUCCESS
)
{
ap_log_error
(
APLOG_MARK
,
APLOG_CRIT
,
rv
,
s
,
"mod_tequila : could not create tequila_log_lock"
);
return
HTTP_INTERNAL_SERVER_ERROR
;
}
url_is_https
=
APR_RETRIEVE_OPTIONAL_FN
(
ssl_is_https
);
#if APR_USE_SYSVSEM_SERIALIZE
rv
=
unixd_set_global_mutex_perms
(
tequila_log_lock
);
if
(
rv
!=
AP_SUCCESS
)
{
ap_log_error
(
APLOG_MARK
,
APLOG_CRIT
,
rv
,
s
,
"mod_tequila : Could not set permissions on "
"tequila_log_lock; check User and Group directives"
);
return
HTTP_INTERNAL_SERVER_ERROR
;
}
#endif
for
(;
s
;
s
=
s
->
next
)
{
openteqlog
(
s
,
p
);
}
return
OK
;
}
#else
static
void
fd_lock
(
request_rec
*
r
,
int
fd
)
{
int
rc
=
-
1
;
#ifdef USE_FCNTL
lock_it
.
l_whence
=
SEEK_SET
;
/* from current point */
lock_it
.
l_start
=
0
;
/* -"- */
lock_it
.
l_len
=
0
;
/* until end of file */
lock_it
.
l_type
=
F_WRLCK
;
/* set exclusive/write lock */
lock_it
.
l_pid
=
0
;
/* pid not actually interesting */
while
(((
rc
=
fcntl
(
fd
,
F_SETLKW
,
&
lock_it
))
<
0
)
&&
(
errno
==
EINTR
))
continue
;
#endif
#ifdef USE_FLOCK
while
(((
rc
=
flock
(
fd
,
LOCK_EX
))
<
0
)
&&
(
errno
==
EINTR
))
continue
;
#endif
#ifdef USE_LOCKING
/* Lock the first byte, always, assume we want to append
and seek to the end afterwards */
lseek
(
fd
,
0
,
SEEK_SET
);
rc
=
_locking
(
fd
,
_LK_LOCK
,
1
);
lseek
(
fd
,
0
,
SEEK_END
);
#endif
#ifdef NETWARE
if
((
locking_sem
!=
0
)
&&
(
TimedWaitOnLocalSemaphore
(
locking_sem
,
10000
)
!=
0
))
rc
=
-
1
;
else
rc
=
1
;
#endif
if
(
rc
<
0
)
{
fprintf
(
stderr
,
"mod_tequila: failed to lock file descriptor
\n
"
);
exit
(
1
);
}
return
;
}
static
void
fd_unlock
(
request_rec
*
r
,
int
fd
)
{
int
rc
;
#ifdef USE_FCNTL
unlock_it
.
l_whence
=
SEEK_SET
;
/* from current point */
unlock_it
.
l_start
=
0
;
/* -"- */
unlock_it
.
l_len
=
0
;
/* until end of file */
unlock_it
.
l_type
=
F_UNLCK
;
/* unlock */
unlock_it
.
l_pid
=
0
;
/* pid not actually interesting */
rc
=
fcntl
(
fd
,
F_SETLKW
,
&
unlock_it
);
#endif
#ifdef USE_FLOCK
rc
=
flock
(
fd
,
LOCK_UN
);
#endif
#ifdef USE_LOCKING
lseek
(
fd
,
0
,
SEEK_SET
);
rc
=
_locking
(
fd
,
_LK_UNLCK
,
1
);
lseek
(
fd
,
0
,
SEEK_END
);
#endif
#ifdef NETWARE
if
(
locking_sem
)
SignalLocalSemaphore
(
locking_sem
);
rc
=
1
;
#endif
if
(
rc
<
0
)
return
;
}
static
void
init_module
(
server_rec
*
s
,
AP_POOL
*
p
)
{
proxy_available
=
(
ap_find_linked_module
(
"mod_proxy.c"
)
!=
NULL
);
for
(;
s
;
s
=
s
->
next
)
{
openteqlog
(
s
,
p
);
}
}
#endif
static
void
set_cookie
(
request_rec
*
r
,
char
*
key
)
{
tequila_perdir_conf
*
dconf
;
char
*
cookie
;
unsigned
pathhash
;
char
*
uripath
;
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
((
dconf
==
NULL
)
||
(
dconf
->
path
==
NULL
))
return
;
teqlog
(
r
,
4
,
"set_cookie: uri = %s, dconf->path = %s"
,
r
->
uri
,
dconf
->
path
);
pathhash
=
hash
(
dconf
->
path
);
cookie
=
AP_SPRINTF
(
r
->
pool
,
"teqkey:%u=%s; path=%s"
,
pathhash
,
key
,
"/"
);
teqlog
(
r
,
2
,
"set_cookie: cookie = %s"
,
cookie
);
AP_TABLESET
(
r
->
err_headers_out
,
"Set-Cookie"
,
cookie
);
return
;
}
static
char
*
getkey
(
request_rec
*
r
)
{
char
*
key
=
(
char
*
)
0
;
int
nbytes
;
char
*
keydeb
;
char
*
args
=
NULL
;
const
char
*
cookie
;
keyfromcookie
=
0
;
//
// Try URL first
//
args
=
r
->
args
;
teqlog
(
r
,
4
,
"getkey: args : %s"
,
args
);
if
(
args
&&
(
keydeb
=
strstr
(
args
,
"key="
)))
{
char
*
s
=
keydeb
+
4
;
while
(
*
s
&&
(
*
s
!=
'&'
))
s
++
;
if
(
*
s
==
'&'
)
{
*
s
=
'\0'
;
key
=
AP_STRDUP
(
r
->
pool
,
keydeb
+
4
);
*
s
=
'&'
;
}
else
{
key
=
AP_STRDUP
(
r
->
pool
,
keydeb
+
4
);
}
}
if
(
key
)
return
key
;
//
// No key in URL, try cookies.
//
if
(
r
->
main
)
{
/* subrequest */
const
char
*
cookie
=
AP_TABLEGET
(
r
->
main
->
err_headers_out
,
"Set-Cookie"
);
if
(
cookie
)
key
=
getkeyfromcookie
(
r
,
cookie
);
if
(
key
)
{
keyfromcookie
=
1
;
return
key
;
}
}
cookie
=
AP_TABLEGET
(
r
->
headers_in
,
"Cookie"
);
if
(
cookie
)
key
=
getkeyfromcookie
(
r
,
cookie
);
if
(
key
)
{
keyfromcookie
=
1
;
return
key
;
}
teqlog
(
r
,
5
,
"getkey: No key found"
);
return
NULL
;
}
static
char
*
getkeyfromcookie
(
request_rec
*
r
,
const
char
*
cookie
)
{
tequila_perdir_conf
*
dconf
;
char
*
s
,
*
c
,
*
h
,
*
value
,
*
cook
,
*
pathhash
;
if
(
!
cookie
)
{
teqlog
(
r
,
99
,
"getkeyfromcookie:no cookie found"
);
return
(
char
*
)
0
;
}
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
((
dconf
==
NULL
)
||
(
dconf
->
path
==
NULL
))
return
(
char
*
)
0
;
pathhash
=
AP_SPRINTF
(
r
->
pool
,
"%u"
,
hash
(
dconf
->
path
));
while
(
cookie
&&
(
value
=
strstr
(
cookie
,
"teqkey:"
)))
{
char
*
hashbuf
,
*
hashend
,
*
cookbuf
,
*
cookend
;
value
+=
strlen
(
"teqkey:"
);
hashbuf
=
AP_STRDUP
(
r
->
pool
,
value
);
hashend
=
strchr
(
hashbuf
,
'='
);
if
(
hashend
)
*
hashend
=
'\0'
;
cookbuf
=
hashend
+
1
;
cookend
=
strchr
(
cookbuf
,
';'
);
if
(
cookend
)
*
cookend
=
'\0'
;
if
(
!
strcmp
(
hashbuf
,
pathhash
))
return
cookbuf
;
cookie
=
cookend
?
cookend
+
2
:
NULL
;
}
return
(
char
*
)
0
;
}
static
unsigned
rantable
[]
=
{
747323161
,
163537951
,
559183603
,
535991927
,
55228437
,
902893215
,
702443576
,
383259134
,
470551003
,
409377227
,
762435312
,
12954216
,
630240577
,
429738414
,
747966939
,
524041125
,
52534467
,
937350059
,
721602759
,
771156665
,
488380559
,
4064707
,
292023389
,
958556516
,
108153117
,
757587078
,
10845887
,
667567374
,
162364313
,
635823247
,
605561322
,
700796899
,
133054934
,
174699191
,
527643367
,
878021462
,
336077656
,
744595963
,
110892239
,
578143469
,
938117957
,
189405922
,
310366059
,
662568395
,
302540930
,
415351040
,
152178176
,
439074741
,
546037787
,
729518521
,
565999420
,
94247440
,
488856080
,
620697805
,
704311001
,
427860482
,
958415115
,
443025647
,
602304977
,
275428698
,
305330063
,
989115693
,
12720429
,
762708049
,
53701004
,
123361206
,
755590333
,
111032844
,
241454650
,
222111569
,
571301928
,
740799682
,
978018134
,
587842825
,
666902019
,
771909829
,
392389580
,
705378773
,
802997113
,
757532942
,
18403645
,
535199863
,
443011788
,
770089618
,
354719086
,
166649883
,
562152615
,
207773813
,
798374317
,
548274697
,
191292350
,
243399978
,
585649237
,
746210183
,
620179656
,
517625624
,
139966790
,
911997570
,
132500521
,
449348102
,
517478498
,
125893297
,
767028767
,
826990710
,
576848567
,
935575809
,
987216614
,
640287812
,
350307482
,
164030500
,
343584660
,
778009689
,
385756146
,
96474262
,
828151765
,
528953582
,
479452185
,
387811215
,
391990207
,
277922478
,
812303128
,
763943999
,
257744410
,
582803839
,
275887479
,
25822136
,
915890024
,
434924082
,
};
static
unsigned
hash
(
char
*
string
)
{
unsigned
h
=
0
;
while
(
*
string
)
{
unsigned
char
i
=
*
string
;
unsigned
char
l
=
((
h
>>
24
)
&
0x000000ff
);
h
=
((
h
<<
8
)
|
l
)
^
rantable
[
i
];
string
++
;
}
return
(
h
);
}
static
const
char
c2x_table
[]
=
"0123456789ABCDEF"
;
static
char
*
escape_url
(
AP_POOL
*
p
,
const
char
*
url
)
{
char
*
copy
;
const
char
*
u
;
char
*
c
;
if
(
url
==
NULL
)
return
NULL
;
copy
=
AP_ALLOC
(
p
,
3
*
strlen
(
url
)
+
3
);
u
=
(
const
char
*
)
url
;
c
=
(
char
*
)
copy
;
while
(
*
u
)
{
if
((
*
u
==
' '
)
||
(
*
u
==
'?'
)
||
(
*
u
==
'&'
)
||
(
*
u
==
'/'
))
{
*
c
++
=
'%'
;
*
c
++
=
c2x_table
[
*
u
>>
4
];
*
c
++
=
c2x_table
[
*
u
&
0xf
];
}
else
{
*
c
++
=
*
u
;
}
++
u
;
}
*
c
=
'\0'
;
return
copy
;
}
static
char
*
unescape_url
(
AP_POOL
*
p
,
const
char
*
url
)
{
char
*
copy
;
const
char
*
u
;
char
*
c
;
if
(
url
==
NULL
)
return
NULL
;
copy
=
AP_ALLOC
(
p
,
strlen
(
url
)
+
1
);
u
=
(
const
char
*
)
url
;
c
=
(
char
*
)
copy
;
while
(
*
u
)
{
if
(
*
u
==
'%'
)
{
int
hexcode
;
u
++
;
if
(
*
u
&&
sscanf
(
u
,
"%2x"
,
&
hexcode
))
{
*
c
++
=
hexcode
;
u
++
;
u
++
;
}
else
{
*
c
++
=
'%'
;
*
c
++
=
*
u
++
;
*
c
++
=
*
u
++
;
}
}
else
{
*
c
++
=
*
u
++
;
}
}
*
c
=
'\0'
;
return
copy
;
}
static
int
createserverrequest
(
request_rec
*
r
)
{
tequila_perdir_conf
*
dconf
;
tequila_global_conf
*
gconf
;
char
*
teqserver
,
*
proto
,
*
tequrl
,
*
args
,
*
postline
,
*
hostline
,
*
contlen
,
*
res
,
*
key
;
int
status
;
int
port
=
80
;
int
https
;
int
argslen
;
int
maxresult
=
1024
;
char
result
[
1025
];
int
len
;
if
(
!
r
||
!
r
->
server
)
return
DECLINED
;
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
r
->
server
->
module_config
,
&
tequila_module
);
#ifdef APACHE2
https
=
url_is_https
&&
url_is_https
(
r
->
connection
);
teqlog
(
r
,
2
,
"createserverrequest: url_is_https = %d"
,
https
);
proto
=
https
?
"https"
:
"http"
;
#else
proto
=
"http"
;
#endif
teqserver
=
gconf
->
teqserver
;
if
(
teqserver
==
NULL
)
teqserver
=
defaultteqserver
;
tequrl
=
AP_STRCAT
(
r
->
pool
,
"https://"
,
teqserver
,
"/cgi-bin/tequila/auth"
,
NULL
);
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
((
dconf
==
NULL
)
||
(
dconf
->
allowif
==
NULL
))
return
HTTP_FORBIDDEN
;
if
(
dconf
->
resource
)
{
args
=
AP_STRCAT
(
r
->
pool
,
"resource="
,
dconf
->
resource
,
"
\n
"
,
NULL
);
}
else
{
char
*
urlaccess
,
*
filter
,
*
allows
,
*
servname
,
*
request
;
int
port
=
ap_get_server_port
(
r
);
if
(
port
!=
80
)
{
char
sport
[
8
];
sprintf
(
sport
,
"%d"
,
port
);
urlaccess
=
AP_STRCAT
(
r
->
pool
,
proto
,
"://"
,
r
->
hostname
,
":"
,
sport
,
r
->
uri
,
NULL
);
}
else
{
urlaccess
=
AP_STRCAT
(
r
->
pool
,
proto
,
"://"
,
r
->
hostname
,
r
->
uri
,
NULL
);
}
if
(
r
->
args
)
urlaccess
=
AP_STRCAT
(
r
->
pool
,
urlaccess
,
"?"
,
r
->
args
,
NULL
);
filter
=
getFilter
(
r
);
if
(
filter
==
NULL
)
return
DECLINED
;
args
=
AP_STRCAT
(
r
->
pool
,
"urlaccess="
,
urlaccess
,
"
\n
"
,
"path="
,
dconf
->
path
,
"
\n
"
,
"require="
,
filter
,
"
\n
"
,
NULL
);
allows
=
getAllows
(
r
);
if
(
allows
)
{
teqlog
(
r
,
9
,
"createserverrequest: allows = %s."
,
allows
);
args
=
AP_STRCAT
(
r
->
pool
,
args
,
"allows="
,
allows
,
"
\n
"
,
NULL
);
}
servname
=
dconf
->
servname
;
if
(
!
servname
)
{
servname
=
AP_STRCAT
(
r
->
pool
,
"Document "
,
r
->
server
->
server_hostname
,
":"
,
dconf
->
path
,
NULL
);
}
args
=
AP_STRCAT
(
r
->
pool
,
args
,
"service="
,
servname
,
"
\n
"
,
NULL
);
request
=
getRequest
(
r
);
if
(
request
)
{
teqlog
(
r
,
9
,
"createserverrequest: request = %s."
,
request
);
args
=
AP_STRCAT
(
r
->
pool
,
args
,
"request="
,
request
,
"
\n
"
,
NULL
);
}
}
teqlog
(
r
,
9
,
"createserverrequest: args = %s"
,
args
);
argslen
=
strlen
(
args
);
postline
=
"POST /cgi-bin/tequila/createrequest HTTP/1.0
\r\n
"
;
hostline
=
AP_STRCAT
(
r
->
pool
,
"Host: "
,
teqserver
,
"
\r\n
"
,
NULL
);
contlen
=
AP_SPRINTF
(
r
->
pool
,
"Content-length: %d
\r\n
"
,
argslen
);
#ifdef USESSL
if
(
!
gconf
->
usessl
)
#endif
{
ssize_t
wsize
;
int
sock
,
tot
;
struct
sockaddr_in
sockaddr
;
struct
hostent
*
hostentry
;
hostentry
=
gethostbyname
(
teqserver
);
if
(
!
hostentry
)
{
teqlog
(
r
,
2
,
"createserverrequest: cannot get address of %s."
,
teqserver
);
close
(
sock
);
return
HTTP_FORBIDDEN
;
}
bzero
((
char
*
)
&
sockaddr
,
sizeof
(
sockaddr
));
bcopy
(
hostentry
->
h_addr
,
(
char
*
)
&
sockaddr
.
sin_addr
,
hostentry
->
h_length
);
sockaddr
.
sin_family
=
hostentry
->
h_addrtype
;
sockaddr
.
sin_port
=
htons
(
port
);
sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
sock
<
0
)
{
teqlog
(
r
,
2
,
"createserverrequest: cannot create socket."
);
return
HTTP_FORBIDDEN
;
}
status
=
connect
(
sock
,
(
struct
sockaddr
*
)
&
sockaddr
,
sizeof
(
sockaddr
));
if
(
status
<
0
)
{
teqlog
(
r
,
2
,
"createserverrequest: cannot connect to socket."
);
return
HTTP_FORBIDDEN
;
}
wsize
=
write
(
sock
,
postline
,
strlen
(
postline
));
wsize
=
write
(
sock
,
hostline
,
strlen
(
hostline
));
wsize
=
write
(
sock
,
contlen
,
strlen
(
contlen
));
wsize
=
write
(
sock
,
"
\r\n
"
,
2
);
wsize
=
write
(
sock
,
args
,
argslen
);
wsize
=
write
(
sock
,
"
\r\n
"
,
2
);
tot
=
0
;
while
(
len
=
read
(
sock
,
result
+
tot
,
maxresult
-
tot
))
{
if
(
len
<
0
)
break
;
tot
+=
len
;
if
(
tot
>
maxresult
)
{
tot
=
maxresult
;
break
;
}
result
[
tot
]
=
'\0'
;
}
close
(
sock
);
}
#ifdef USESSL
else
{
SSLenv
*
sslenv
=
opensslsocket
(
r
,
teqserver
,
443
);
int
tot
=
0
;
if
(
!
sslenv
)
{
teqlog
(
r
,
2
,
"createserverrequest: cannot open SSL connection to %s."
,
teqserver
);
return
HTTP_FORBIDDEN
;
}
BIO_write
(
sslenv
->
bio
,
postline
,
strlen
(
postline
));
BIO_write
(
sslenv
->
bio
,
hostline
,
strlen
(
hostline
));
BIO_write
(
sslenv
->
bio
,
contlen
,
strlen
(
contlen
));
BIO_write
(
sslenv
->
bio
,
"
\r\n
"
,
2
);
BIO_write
(
sslenv
->
bio
,
args
,
argslen
);
BIO_write
(
sslenv
->
bio
,
"
\r\n
"
,
2
);
while
(
len
=
BIO_read
(
sslenv
->
bio
,
result
+
tot
,
maxresult
-
tot
))
{
if
(
len
<
0
)
break
;
tot
+=
len
;
if
(
tot
>
maxresult
)
{
tot
=
maxresult
;
break
;
}
}
result
[
tot
]
=
'\0'
;
closesslsocket
(
sslenv
);
}
#endif
teqlog
(
r
,
99
,
"createserverrequest: result = %s"
,
result
);
res
=
result
;
while
(
*
res
&&
(
*
res
!=
' '
))
res
++
;
if
(
!
sscanf
(
res
,
"%d"
,
&
status
))
{
teqlog
(
r
,
2
,
"createserverrequest: invalid status line"
);
return
HTTP_FORBIDDEN
;
}
if
(
status
!=
200
)
{
teqlog
(
r
,
2
,
"createserverrequest: invalid status : %d"
,
status
);
return
HTTP_FORBIDDEN
;
}
key
=
NULL
;
while
(
*
res
)
{
while
(
*
res
&&
*
res
!=
'\n'
&&
*
res
!=
'\r'
)
res
++
;
if
(
!*
res
)
break
;
while
(
*
res
==
'\n'
||
*
res
==
'\r'
)
res
++
;
if
(
strncmp
(
res
,
"key="
,
4
)
==
0
)
{
char
*
end
;
res
+=
4
;
end
=
res
;
while
(
*
end
&&
(
*
end
!=
'\n'
))
end
++
;
*
end
=
'\0'
;
key
=
AP_STRDUP
(
r
->
pool
,
res
);
break
;
}
}
if
(
!
key
)
{
teqlog
(
r
,
2
,
"createserverrequest: Bad response from local Tequila server"
);
return
HTTP_FORBIDDEN
;
}
r
->
args
=
AP_STRCAT
(
r
->
pool
,
"requestkey="
,
key
,
NULL
);
r
->
filename
=
AP_STRCAT
(
r
->
pool
,
tequrl
,
"?"
,
r
->
args
,
NULL
);
teqlog
(
r
,
3
,
"createserverrequest: r->filename = %s"
,
r
->
filename
);
AP_TABLESET
(
r
->
headers_out
,
"Location"
,
r
->
filename
);
AP_TABLESET
(
r
->
headers_out
,
"Pragma"
,
"no-cache"
);
return
HTTP_MOVED_PERMANENTLY
;
}
static
Session
*
fetchattributes
(
request_rec
*
r
,
const
char
*
requestkey
)
{
tequila_perdir_conf
*
dconf
;
tequila_global_conf
*
gconf
;
char
*
hostline
,
*
teqserver
,
*
res
;
int
status
;
int
port
=
80
;
Session
*
session
;
int
maxresult
=
8192
;
char
result
[
8193
];
int
len
;
char
*
org
,
*
user
,
*
host
,
*
path
,
*
filter
=
""
;
teqlog
(
r
,
2
,
"fetchattributes: requestkey = %s"
,
requestkey
);
if
(
!
r
||
!
r
->
server
)
{
error
(
r
,
"Unable to contact Tequila server"
);
return
NULL
;
}
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
r
->
server
->
module_config
,
&
tequila_module
);
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
teqserver
=
gconf
->
teqserver
;
if
(
teqserver
==
NULL
)
teqserver
=
defaultteqserver
;
hostline
=
AP_STRCAT
(
r
->
pool
,
"Host: "
,
teqserver
,
"
\r\n
"
,
NULL
);
#ifdef USESSL
if
(
!
gconf
->
usessl
&&
(
!
dconf
||
!
dconf
->
resource
))
#endif
{
ssize_t
wsize
;
int
sock
,
tot
;
struct
sockaddr_in
sockaddr
;
struct
hostent
*
hostentry
;
char
*
getline
=
AP_STRCAT
(
r
->
pool
,
"GET /cgi-bin/tequila/fetchattributes?key="
,
requestkey
,
" HTTP/1.0
\r\n
"
,
NULL
);
hostentry
=
gethostbyname
(
teqserver
);
if
(
hostentry
==
NULL
)
{
close
(
sock
);
teqlog
(
r
,
2
,
"fetchattributes: cannot get address of %s."
,
teqserver
);
error
(
r
,
"Unable to get address of Tequila server"
);
return
NULL
;
}
bzero
((
char
*
)
&
sockaddr
,
sizeof
(
sockaddr
));
bcopy
(
hostentry
->
h_addr
,
(
char
*
)
&
sockaddr
.
sin_addr
,
hostentry
->
h_length
);
sockaddr
.
sin_family
=
hostentry
->
h_addrtype
;
sockaddr
.
sin_port
=
htons
(
port
);
sock
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
sock
<
0
)
{
teqlog
(
r
,
2
,
"fetchattributes: cannot create socket."
);
error
(
r
,
"Unable to contact Tequila server"
);
return
NULL
;
}
status
=
connect
(
sock
,
(
struct
sockaddr
*
)
&
sockaddr
,
sizeof
(
sockaddr
));
if
(
status
<
0
)
{
teqlog
(
r
,
2
,
"fetchattributes: cannot connect to socket."
);
error
(
r
,
"Unable to connect to Tequila server"
);
return
NULL
;
}
wsize
=
write
(
sock
,
getline
,
strlen
(
getline
));
wsize
=
write
(
sock
,
hostline
,
strlen
(
hostline
));
wsize
=
write
(
sock
,
"
\r\n
"
,
2
);
tot
=
0
;
while
(
len
=
read
(
sock
,
result
+
tot
,
maxresult
-
tot
))
{
if
(
len
<
0
)
break
;
tot
+=
len
;
if
(
tot
>
maxresult
)
{
tot
=
maxresult
;
break
;
}
result
[
tot
]
=
'\0'
;
}
close
(
sock
);
}
#ifdef USESSL
else
{
int
tot
=
0
;
char
*
scriptname
=
(
dconf
&&
dconf
->
resource
)
?
"/cgi-bin/tequilac"
:
"/cgi-bin/tequila"
;
char
*
getline
=
AP_STRCAT
(
r
->
pool
,
"GET "
,
scriptname
,
"/fetchattributes?key="
,
requestkey
,
" HTTP/1.0
\r\n
"
,
NULL
);
SSLenv
*
sslenv
=
opensslsocket
(
r
,
teqserver
,
443
);
if
(
!
sslenv
)
{
teqlog
(
r
,
2
,
"fetchattributes: cannot open SSL connection to %s."
,
teqserver
);
error
(
r
,
"Unable to open SSL connection to Tequila server"
);
return
NULL
;
}
BIO_write
(
sslenv
->
bio
,
getline
,
strlen
(
getline
));
BIO_write
(
sslenv
->
bio
,
hostline
,
strlen
(
hostline
));
BIO_write
(
sslenv
->
bio
,
"
\r\n
"
,
2
);
while
(
len
=
BIO_read
(
sslenv
->
bio
,
result
+
tot
,
maxresult
-
tot
))
{
if
(
len
<
0
)
break
;
tot
+=
len
;
if
(
tot
>
maxresult
)
{
tot
=
maxresult
;
break
;
}
}
result
[
tot
]
=
'\0'
;
closesslsocket
(
sslenv
);
}
#endif
res
=
result
;
while
(
*
res
&&
(
*
res
!=
' '
))
res
++
;
if
(
!
sscanf
(
res
,
"%d"
,
&
status
))
{
char
*
err
;
teqlog
(
r
,
2
,
"fetchattributes: invalid status line"
);
err
=
AP_STRCAT
(
r
->
pool
,
"Tequila server returns invalid line : "
,
result
,
NULL
);
error
(
r
,
err
);
return
NULL
;
}
if
(
status
==
451
)
{
/* Invalid key.*/
teqlog
(
r
,
2
,
"fetchattributes: key %s unknown to server."
,
requestkey
);
return
NULL
;
}
if
(
status
!=
200
)
{
teqlog
(
r
,
2
,
"fetchattributes: invalid status : %d"
,
status
);
while
(
*
res
&&
(
*
res
!=
'\n'
))
res
++
;
*
res
=
'\0'
;
error
(
r
,
result
);
return
NULL
;
}
while
(
*
res
)
{
int
sep
=
0
;
while
(
*
res
&&
*
res
!=
'\n'
&&
*
res
!=
'\r'
)
res
++
;
while
(
*
res
==
'\n'
||
*
res
==
'\r'
)
{
if
(
*
res
==
'\n'
)
sep
++
;
res
++
;
}
if
(
sep
>
1
)
break
;
}
session
=
(
Session
*
)
AP_ALLOC
(
r
->
pool
,
sizeof
(
Session
));
session
->
attrs
=
AP_TABLE_MAKE
(
r
->
pool
,
16
);
while
(
*
res
)
{
char
*
name
=
res
;
while
(
*
res
&&
*
res
!=
'='
&&
*
res
!=
'\n'
&&
*
res
!=
'\r'
)
res
++
;
if
(
*
res
==
'='
)
{
char
*
value
;
*
res
=
'\0'
;
res
++
;
value
=
res
;
while
(
*
res
&&
*
res
!=
'\n'
&&
*
res
!=
'\r'
)
res
++
;
if
(
*
res
)
*
res
++
=
'\0'
;
if
(
strcmp
(
name
,
"org"
)
==
0
)
{
org
=
value
;
}
else
if
(
strcmp
(
name
,
"user"
)
==
0
)
{
user
=
value
;
}
else
if
(
strcmp
(
name
,
"host"
)
==
0
)
{
host
=
value
;
}
else
if
(
strcmp
(
name
,
"path"
)
==
0
)
{
path
=
value
;
}
else
if
(
strcmp
(
name
,
"require"
)
==
0
)
{
filter
=
value
;
}
else
{
AP_TABLESET
(
session
->
attrs
,
name
,
value
);
}
}
while
(
*
res
==
'\n'
||
*
res
==
'\r'
)
res
++
;
}
if
(
!
org
||
!
user
||
!
host
||
!
path
)
{
teqlog
(
r
,
2
,
"fetchattributes: invalid response from Tequila server."
);
error
(
r
,
"Invalid response from Tequila server."
);
return
NULL
;
}
substsepar
(
filter
,
':'
,
'&'
);
session
->
key
=
AP_STRDUP
(
r
->
pool
,
requestkey
);
session
->
org
=
AP_STRDUP
(
r
->
pool
,
org
);
session
->
user
=
AP_STRDUP
(
r
->
pool
,
user
);
session
->
host
=
AP_STRDUP
(
r
->
pool
,
host
);
session
->
path
=
AP_STRDUP
(
r
->
pool
,
path
);
session
->
filter
=
filter
?
AP_STRDUP
(
r
->
pool
,
filter
)
:
NULL
;
writesession
(
r
,
gconf
->
sessdir
,
session
);
return
session
;
}
static
int
setenvvars
(
request_rec
*
r
)
{
AP_TABLE_T
*
env
=
r
->
subprocess_env
;
const
AP_ARRAY_HEADER_T
*
hdrs_attrs
;
const
AP_TABLE_ENTRY_T
*
hdrs
;
tequila_perdir_conf
*
dconf
;
Session
*
session
;
int
i
;
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
!
dconf
||
!
dconf
->
session
)
return
OK
;
session
=
dconf
->
session
;
AP_TABLESET
(
env
,
"REMOTE_USER"
,
session
->
user
);
AP_TABLESET
(
env
,
"HTTP_TEQUILA_KEY"
,
session
->
key
);
AP_TABLESET
(
env
,
"HTTP_TEQUILA_ORG"
,
session
->
org
);
AP_TABLESET
(
env
,
"HTTP_TEQUILA_USER"
,
session
->
user
);
AP_TABLESET
(
env
,
"HTTP_TEQUILA_HOST"
,
session
->
host
);
AP_TABLESET
(
env
,
"HTTP_TEQUILA_PATH"
,
session
->
path
);
AP_TABLESET
(
env
,
"HTTP_TEQUILA_FILTER"
,
session
->
filter
);
hdrs_attrs
=
AP_TABLE_ELTS
(
session
->
attrs
);
hdrs
=
(
const
AP_TABLE_ENTRY_T
*
)
hdrs_attrs
->
elts
;
for
(
i
=
0
;
i
<
hdrs_attrs
->
nelts
;
i
++
)
{
char
*
key
,
*
k
,
*
attrname
;
if
(
!
hdrs
[
i
].
key
)
continue
;
key
=
AP_STRDUP
(
r
->
pool
,
hdrs
[
i
].
key
);
k
=
key
;
while
(
*
k
)
{
*
k
=
AP_TOUPPER
(
*
k
);
k
++
;
}
attrname
=
AP_STRCAT
(
r
->
pool
,
"HTTP_TEQUILA_"
,
key
,
NULL
);
AP_TABLESET
(
env
,
attrname
,
hdrs
[
i
].
val
);
}
return
OK
;
}
static
void
error
(
request_rec
*
r
,
char
*
msg
)
{
#ifdef APACHE2
ap_set_content_type
(
r
,
"text/html; charset=iso-8859-1"
);
#else
r
->
content_type
=
"text/html; charset=iso-8859-1"
;
#endif
ap_rvputs
(
r
,
DOCTYPE_HTML_2_0
"<html><head>
\n
<title>"
,
"Tequila error"
,
"</title>
\n
</head><body>
\n
<h1>"
,
"Tequila error"
,
"</h1>
\n
"
,
NULL
);
ap_rvputs
(
r
,
msg
,
NULL
);
ap_rvputs
(
r
,
ap_psignature
(
"<hr>
\n
"
,
r
),
NULL
);
ap_rvputs
(
r
,
"</body></html>
\n
"
,
NULL
);
ap_finalize_request_protocol
(
r
);
}
#ifdef USESSL
static
SSLenv
*
opensslsocket
(
request_rec
*
r
,
char
*
host
,
int
port
)
{
char
hostport
[
128
];
SSL
*
ssl
;
BIO
*
bio
;
SSL_CTX
*
ctx
;
SSLenv
*
sslenv
;
void
*
sconf
=
r
->
server
->
module_config
;
tequila_global_conf
*
gconf
;
tequila_perdir_conf
*
dconf
;
sprintf
(
hostport
,
"%s:%d"
,
host
,
port
);
teqlog
(
r
,
1
,
"opensslsocket:Connecting to %s."
,
hostport
);
ctx
=
SSL_CTX_new
(
SSLv23_client_method
());
if
(
ctx
==
NULL
)
{
teqlog
(
r
,
1
,
"Unable to allocate SSL context."
);
return
NULL
;
}
gconf
=
(
tequila_global_conf
*
)
ap_get_module_config
(
sconf
,
&
tequila_module
);
dconf
=
(
tequila_perdir_conf
*
)
ap_get_module_config
(
r
->
per_dir_config
,
&
tequila_module
);
if
(
gconf
->
cafile
)
{
int
loadverif
=
SSL_CTX_load_verify_locations
(
ctx
,
gconf
->
cafile
,
NULL
);
if
(
!
loadverif
)
{
teqlog
(
r
,
1
,
"opensslsocket:Error loading trust store."
);
ERR_print_errors_fp
(
stderr
);
SSL_CTX_free
(
ctx
);
return
NULL
;
}
}
bio
=
BIO_new_ssl_connect
(
ctx
);
BIO_get_ssl
(
bio
,
&
ssl
);
SSL_set_mode
(
ssl
,
SSL_MODE_AUTO_RETRY
);
if
(
dconf
->
resource
&&
dconf
->
keyfile
&&
dconf
->
certfile
)
{
teqlog
(
r
,
2
,
"opensslsocket:resource = %s, keyfile = %s, certfile = %s."
,
dconf
->
resource
,
dconf
->
keyfile
,
dconf
->
certfile
);
SSL_use_certificate_file
(
ssl
,
dconf
->
certfile
,
SSL_FILETYPE_PEM
);
SSL_use_PrivateKey_file
(
ssl
,
dconf
->
keyfile
,
SSL_FILETYPE_PEM
);
}
BIO_set_conn_hostname
(
bio
,
hostport
);
if
(
BIO_do_connect
(
bio
)
<=
0
)
{
teqlog
(
r
,
1
,
"opensslsocket:Error attempting to connect."
);
ERR_print_errors_fp
(
stderr
);
BIO_free_all
(
bio
);
SSL_CTX_free
(
ctx
);
return
NULL
;
}
if
(
gconf
->
checkservername
)
{
X509
*
cert
=
SSL_get_peer_certificate
(
ssl
);
if
(
!
checkcertificate
(
r
,
cert
,
host
))
{
teqlog
(
r
,
1
,
"opensslsocket:Bad certificate."
);
BIO_free_all
(
bio
);
SSL_CTX_free
(
ctx
);
return
NULL
;
}
}
if
(
gconf
->
cafile
)
{
int
verif
;
teqlog
(
r
,
1
,
"opensslsocket:Checking server certificate chain."
);
verif
=
SSL_get_verify_result
(
ssl
);
if
(
verif
!=
X509_V_OK
)
{
teqlog
(
r
,
1
,
"opensslsocket:Certificate verification error: %d."
,
SSL_get_verify_result
(
ssl
));
BIO_free_all
(
bio
);
SSL_CTX_free
(
ctx
);
return
NULL
;
}
}
sslenv
=
(
SSLenv
*
)
malloc
(
sizeof
(
SSLenv
*
));
sslenv
->
ctx
=
ctx
;
sslenv
->
bio
=
bio
;
return
sslenv
;
}
static
void
closesslsocket
(
SSLenv
*
sslenv
)
{
BIO_free_all
(
sslenv
->
bio
);
SSL_CTX_free
(
sslenv
->
ctx
);
free
(
sslenv
);
}
static
int
checkcertificate
(
request_rec
*
r
,
X509
*
cert
,
char
*
host
)
{
STACK_OF
(
GENERAL_NAME
)
*
gens
;
GENERAL_NAME
*
name
;
X509_NAME
*
subject
=
X509_get_subject_name
(
cert
);
char
buf
[
513
];
char
*
c
;
int
rg
;
int
i
;
teqlog
(
r
,
3
,
"checkcertificate:host = %s, subject = %s."
,
host
,
buf
);
X509_NAME_oneline
(
subject
,
buf
,
512
);
c
=
buf
+
1
;
while
(
*
c
)
{
if
(
!
strncasecmp
(
c
,
"cn="
,
3
))
{
c
+=
3
;
if
(
*
c
==
'('
)
{
char
*
domain
;
char
*
subjects
[
32
];
int
is
=
0
;
char
*
ut
;
int
ns
;
char
tmp
[
128
];
char
*
t
=
++
c
;
while
(
*
t
&&
(
*
t
!=
')'
))
{
char
v
;
char
*
u
=
t
;
while
((
*
u
!=
'|'
)
&&
(
*
u
!=
')'
))
u
++
;
v
=
*
u
;
*
u
=
'\0'
;
subjects
[
is
++
]
=
t
;
t
=
u
+
1
;
if
(
v
!=
'|'
)
break
;
}
if
(
!*
t
)
break
;
ut
=
t
;
while
(
*
ut
&&
(
*
ut
!=
'/'
))
ut
++
;
*
ut
=
'\0'
;
domain
=
t
;
ns
=
is
;
for
(
is
=
0
;
is
<
ns
;
is
++
)
{
strcpy
(
tmp
,
subjects
[
is
]);
strcat
(
tmp
,
domain
);
if
(
!
strcmp
(
tmp
,
host
))
return
1
;
}
c
=
ut
+
1
;
}
else
if
(
*
c
==
'*'
)
{
char
*
s
=
c
+
1
;
char
*
t
=
s
;
char
*
h
;
int
n
;
while
(
*
t
&&
(
*
t
!=
'/'
))
t
++
;
*
t
=
'\0'
;
h
=
host
;
n
=
strlen
(
h
)
-
strlen
(
s
);
if
(
n
>=
0
)
h
+=
n
;
if
(
!
strcasecmp
(
h
,
s
))
return
1
;
c
=
t
+
1
;
}
else
{
char
*
s
=
c
;
while
(
*
s
&&
(
*
s
!=
'/'
))
s
++
;
*
s
=
'\0'
;
if
(
!
strcmp
(
c
,
host
))
return
1
;
c
=
s
+
1
;
}
}
else
{
while
(
*
c
&&
(
*
c
!=
'/'
))
c
++
;
if
(
*
c
)
c
++
;
}
}
gens
=
X509_get_ext_d2i
(
cert
,
NID_subject_alt_name
,
NULL
,
NULL
);
if
(
!
gens
)
return
0
;
teqlog
(
r
,
99
,
"Checking alternate names.."
);
rg
=
sk_GENERAL_NAME_num
(
gens
);
for
(
i
=
0
;
i
<
rg
;
++
i
)
{
const
GENERAL_NAME
*
gn
=
sk_GENERAL_NAME_value
(
gens
,
i
);
if
(
gn
->
type
==
GEN_DNS
)
{
char
*
c
=
(
char
*
)
gn
->
d
.
ia5
->
data
;
char
*
h
=
host
;
if
(
*
c
==
'*'
)
{
int
n
;
++
c
;
n
=
strlen
(
h
)
-
strlen
(
c
);
if
(
n
>=
0
)
h
+=
n
;
}
if
(
!
strcasecmp
(
c
,
h
))
return
1
;
}
}
sk_GENERAL_NAME_free
(
gens
);
return
0
;
}
#endif
/* USESSL */
Event Timeline
Log In to Comment