home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Spezial
/
SPEZIAL2_97.zip
/
SPEZIAL2_97.iso
/
ANWEND
/
ONLINE
/
SREFPRC1
/
HTACCESS.SRF
< prev
next >
Wrap
Text File
|
1997-06-30
|
22KB
|
550 lines
/* ----------------------------------------------------------------------- */
/* SREF_DO_HTACCESS --- a bold lifting of Don Meyer's CHECKAUTH & other stuff:
This will CHECK all the accessfilenames in the tree underneath
file for access privileges, etc.
For details on how to set up an accessfile, see
http://w3.ag.uiuc.edu/DLM/GOHTTP/Auth.Guide.html
REDIRLIST is supported differently (it's checked BEFORE returning,
and only checks the requested file (not the defaultindex)
Also note that when dodirs=1, the DIR.xxx variables are returned,
with NO checking of access privileges.
When dodirs=2, same as 1, but return ALL parameters (used by htaccess
configurator)
Otherwise, access rights are checked.
If access is allowed...
cache_status ',' auto_name_list is returned:
cache_status=0 : do NOT cache
auto_name_list is from the DEFAULTINDEX variable
Note that a check on a file that is generated due to a name pulled from
an earlier lookup of a defaultindex will NEVER generate a new defaultindex
(that is, for each request, the first defaultindex found is used)
If access if forbidden, then an exit is done (with approriate
"forbidden" response )
*/
/* ----------------------------------------------------------------------- */
sref_htaccess:
/* note: who,name,clientport,port,dir,servername will be determined
internally if no value is given */
parse arg sel,file,accessfilename,who,name,clientport,port,dir,SERVERNAME, ,
TEMPFILE,dodirs
file = translate( file, '/', '\')
dir.exclude=' '
secured='1'
PathTo = ''
rest = file
retCode = 0
gotlist=' '
set=' '
/* initialize some variable */
auth.name=' '; auth.type=' ' ; auth.userfile=' ' ; auth.groupfile=' '
auth.index=' '; redirectfile=' '; auth.limit=' '; dir.exclude=' ';
dir.info=' ' ; dir.describe=' ' ; dir.forbid=' ';dir.builder=' '
rx.enablepostprocess=' ' ; rx.builddir=' '
owndir=filespec('d',file)||filespec('p',file)
owndir=upper(translate(owndir,'/','\'))
owndir=strip(owndir,'t','/')
/* find htaccess files;
and if found, extract the parameters, starting at base of directory tree
(thus, own htaccess file is favored */
do while (rest \= '')
restdoggy=right(rest,1)
parse var rest _dir'/'rest
if (right( _dir,1) == ':') then PathTo = _dir
else PathTo = PathTo'/'_dir
if dodirs==3 then do;
if upper(pathto) \= owndir then do
iterate
end
end
goofy=rest ; if goofy=' ' & restdoggy='/' then goofy='/'
if (left(PathTo,3) == '///') then
PathTo = substr(PathTo,2)
else if (goofy \= '') & (right( _dir,1) \= ':') then do
geek1=pathto'/'accessfilename
ACLfile = stream(geek1, 'c', 'query exists')
if (ACLfile \= '') then do /* if not, climb up the tree */
gotlist=gotlist' 'aclfile
Auth.GroupFile = ' '
Auth.Limit = ' '
rc = stream( ACLfile, 'c', 'OPEN READ')
line = linein( ACLfile, 1)
do while (line \= '')
do while( pos(left(line,1), "2009"x) > 0); line = substr(line, 2); end
if ( pos(left(line,1), "#") > 0) then line = substr(line, 2)
if ( left(line,1) == ';') then line = ';COMMENT'
parse var line key ':' val
val = strip(val)
key = translate(key)
if (key = 'AUTHUSERFILE') | (key = 'AUTHGROUPFILE') | (key = 'REDIRLIST') then do
if (pos(':', val ) == 0) then do
val = translate(val, '\', '/')
if (left(val,1) == '\') then val = substr( val, 2)
val = dir || val
end
end
select
when (key = 'AUTHNAME') then Auth.Name = val
when (key = 'AUTHTYPE') then Auth.Type = translate( strip(val))
when (key = 'AUTHUSERFILE') then Auth.UserFile = val
when (key = 'AUTHGROUPFILE') then Auth.GroupFile = val
when (key = 'DEFAULTINDEX') then Auth.Index = val
when (key = 'REDIRLIST') then RedirectFile = val
when (key = 'REDIRFILE') then RedirectFile = val /* bug? in original code */
when (key = 'LIMIT') then Auth.Limit = val
when (key = 'BUILDDIR') then Dir.Build = (val \= '0')
when (key = 'DIR.EXCLUDE') then Dir.Exclude = Dir.Exclude val
when (key = '_DIR.EXCLUDE') then Dir.Exclude = val
when (key = 'DIR.INFO') then Dir.Info = val
when (key = 'DIR.DESCRIBE') then Dir.Describe = val
when (key = 'DIR.FORBID') then Dir.Forbid = (val \= '0')
when (key = 'DIR.BUILDER') then Rx.BuildDir = val
when (key = 'ENABLEPOSTPROCESS') then do
v = left(strip(val),1)
if (pos(v, '012') > 0) then Rx.EnablePostProcess = v
end
otherwise
end
line = linein( ACLfile)
end
rc = stream( ACLfile, 'c', 'close')
end /* this aclfile */
end /* goofy */
end /* climbing up directory tree */
/***** if ay files, and not in info gathering mode, then check access, etc privs */
if auth.type \=' ' & dodirs=0 then do
/* check if trying to get htaccess, group, or password file. If so, forbid! */
parse upper var rest filename
ff2=translate(file,'/','\')
parse upper var Auth.UserFile PassFile /*password file */
if translate(PassFile,'/','\') == ff2 then do
response('forbid', 'is not allowed')
EXIT -1
end
parse upper var Auth.GroupFile AuthGroupFile /* group file */
ff1=translate(authgroupfile,'/','\')
if ( ff1 == Ff2) then do
response('forbid', 'is not allowed')
EXIT -1
END
parse upper var AccessFileName _AccessFileName /* access file */
flimco=upper(filespec('n', File))
if ( _AccessFileName == flimco ) then DO
response('forbid', 'is not allowed')
EXIT -1
END
/* NOT a disallowed file: so fill in missing info */
if clientport="" then clientport=extract('clientport')
if port="" then port=extract('serverport')
if dir="" then dir=datadir()
if servername="" then servername=servername()
if auth.limit \=' ' then do /* augment allowed users set */
parse var Auth.Limit AuthLimitKey _rest
AuthLimitKey = translate( AuthLimitKey)
select
when (AuthLimitKey == 'REQUIRE') then do
Set = strip(_rest)
if (Auth.GroupFile \= '') then do
Set = CompleteSet( Set, Auth.GroupFile)
end
end
when (AuthLimitKey == '') then Set = '' /* a blank causes a resetting */
otherwise DO
Response('notimpl', 'Auth Limit command ['AuthLimitKey'] not recognized.')
EXIT -1
END
end
END /* AUTH LIMIT */
retCode = Auth.Index ; IF RETCODE=' ' THEN RETCODE=0
Auth_Type = Auth.Type
select
when (Auth_Type == 'BASIC') then do
/* Do not allow access to user password file, if requested. */
parse upper var rest filename
parse upper var Auth.UserFile PassFile
if ( upper(translate(PassFile,'/','\')) == upper(translate(File,'/','\'))) then do
response('forbid', 'is not allowed')
EXIT -1
end /* Do */
call authorize Auth.Name, Set
Secured = '0'
end
/* Code to allow restriction to a specific account or machine, */
/* without any challenge. */
when (Auth_Type == 'IDENT') then do
Secured = '0'
/* IDENT client code */
if name=0 | name='' then
name = ClientName()
/* Create a short list of possible machine identity matches... */
_Set = ' '
do i = 1 to words(Set)
if (pos(name, word(Set,i)) > 0) then _Set = _Set' 'Word(Set,i)
else do
rest = word(Set,i)
parse var rest id'@'rest
if ( left(rest,1) == '*') then do
cp = translate(substr(rest,2))
if ( cp == translate(right( name, length(cp)))) then _Set = _Set' 'Word(Set,i)
end
end
end
/* If short list is empty, then we can bypass, as request will be failed.. */
if (words(_Set) == 0) then Set = ''
/* else, if no wildcard userids in short list to eliminate the need to do user identity check.... */
else if (pos('*@', _Set) == 0) then do
if (RxFuncQuery("SockSocket")) then do
rc = RxFuncAdd("SockLoadFuncs","RxSock","SockLoadFuncs")
rc = SockLoadFuncs()
end
Ident = SockSocket('AF_INET','SOCK_STREAM',0)
addr.family = 'AF_INET'
if who="" then who=extract('clientaddr')
addr.addr = who
addr.port = 113
rc = SockConnect(Ident,'addr.')
if rc = 0 Then do
len = SockSend(Ident,clientport','port'0d0a'x)
len = SockRecv(Ident,'data',256)
rc = SockClose(Ident)
parse var data port1 ',' port2 ':' 'USERID:' OS ':' data
data = translate(data,'','0d0a'x)
data = strip(data)
data = translate(data,'_',' ')
end
else do
rc = SockClose(Ident)
data = ''
end
end
else data = ''
username = data'@'name
Set = strip(_Set)
do i = 1 to words(Set)
_check = word(Set, i)
parse var _check first'@'rest
/* check user identity info... */
if (first == '*') then first = data
/* Check machine identity part... */
if (rest == '*') then rest = name
else if ( left(rest,1) == '*') then do
cp = translate(substr(rest,2))
if ( cp == translate(right( name, length(cp)))) then rest = name
end
_check = first'@'rest
if (username == _check) then do
signal gohome9
end
end
Response('forbid', 'could not be honored...')
EXIT -1
end /* IDENT check */
when (Auth_Type == '') then do
end
otherwise DO
response('notimpl', 'referenced an unsupported authentication method')
EXIT -1
END
end /* ident, basic, etc. if */
end
if dodirs=1 then do /* to return list of DIR.xx variables */
return dir.build ',' DIR.exclude ',' dir.info ',' dir.describe ',' dir.forbid ',' rx.builddir
end
if dodirs>1 then do
bigone=gotlist', 'auth.name', 'auth.type', 'auth.userfile', 'auth.groupfile
bigone=bigone', 'auth.index', 'redirectfile', 'auth.limit', 'dir.build
bigone=bigone', 'dir.exclude', 'dir.info', 'dir.describe', 'dir.forbid', 'rx.builddir
bigone=bigone', 'rx.enablepostprocess
return bigone
end
gohome9: nop
/* check for redirection */
foo=doredirect(redirectfile,file) /* if redirect, exit */
/* see if suppress postfilter */
nopostf=rx.enablepostprocess ; nopostfilter=0
if nopostf \=' ' then do
atype=sref_mediatype(file)
select
when nopostf=0 then
nopostfilter=1
when nopostf=1 & upper(atype)\='TEXT/HTML' then
nopostfilter=1
when nopostf=2 then do
FOO1=LASTPOS('.',file) ; anext=' '
if foo1>0 then anext=upper(delstr(file,1,foo1))
IF ABBREV(anext,'SHT')=0 then nopostfilter=1
end
otherwise
nop
end
end
return secured ',' retCode ',' nopostfilter
/* ----------------------------------------------------------------------- */
/* AUTHORIZE -- check access to data is authorized */
/* ----------------------------------------------------------------------- */
/* This routine exits directly if it needs to challenge the client, so it */
/* must be internal. If authorization is valid, it returns to caller. */
/* Argument is the Realm to which the data belongs (this tells the user */
/* which userid/password pair to use. */
/* In this sample filter, the password must be the userid; in a real */
/* application, it would probably be held in a file (such as a .INI file). */
authorize: procedure expose who name clientport PassFile SERVERNAME TEMPFILE port
Set=strip(arg(2))
afield=reqfield('Authorization') /* see if incoming authorization */
parse var afield . m64 . /* get the encoded cookie */
dec=pack64(m64) /* and decode it */
parse var dec user ':' pw /* split to userid and password */
/* [password checking code] */
if (CheckPW( user, pw, PassFile, Set)) then return
/* [End of password checking code] */
realm=strip(arg(1))
'header add WWW-Authenticate: Basic Realm=<'realm'>' /* challenge */
response('unauth', "for realm '"realm"' was not authorized")
EXIT -1
/* ----------------------------------------------------------------------- */
/* CHECKPW -- Check if Password is correct for specified user. */
/* ----------------------------------------------------------------------- */
CheckPW: procedure expose clientport SERVERNAME TEMPFILE port
parse arg user, pw, PassFile, Set
rc = (Set == '') /* set the default - if no SET defined, assume user OK. */
do i = 1 to words(Set)
if (word(Set,i) == user) then rc = 1
end
if (rc) then do
rc = stream( PassFile, 'C', 'OPEN READ')
line = linein( PassFile, 1)
parse var line _user':'_pw
do while (user \= '') & (user \= _user) & (line \= '')
line = linein( PassFile)
parse var line _user':'_pw
end
rc = stream( PassFile, 'c', 'close')
if (line \= '') & (user == _user) then return ( pw == _pw)
end
return (0)
/* ----------------------------------------------------------------------- */
/* COMPLETESET: Fill out the set of users with names from any included groups. */
/* ----------------------------------------------------------------------- */
CompleteSet: procedure EXPOSE SERVERNAME TEMPFILE port
NewSet = ''
parse arg Set, AuthGroupFile
if (AuthGroupFile == '') | (stream( AuthGroupFile, 'c', 'query exists') == '') then return Set
rc = stream( AuthGroupFile, 'C', 'OPEN READ')
do i = 1 to Words(Set)
rc =0
key = word(set,i)
line = linein(AuthGroupFile,1)
do while (rc == 0) & (line \= '')
parse var line GroupName':'Group
Group = strip(Group)
if (GroupName == key) then do
rc = 1
NewSet = Newset Group
end
line = linein(AuthGroupFile)
end
if (rc ==0) then NewSet = NewSet key
end
rc = stream( AuthGroupFile, 'c', 'close')
return strip(NewSet)
/* ----------------------------------------------------------------------- */
/* RESPONSE: Standard [mostly error] responses. */
/* ----------------------------------------------------------------------- */
/* This routine should stay in the main filter program. */
/* Arguments are: response type and extended message information. */
/* It returns the GoServe command to handle the result file. */
response: procedure expose tempfile servername port
parse arg request, message
select
when request='badreq' then use='400 Bad request syntax'
when request='notfound' then use='404 Not found'
when request='forbid' then use='403 Forbidden'
when request='unauth' then use='401 Unauthorized'
when request='notallowed' then use='405 Method not allowed'
when (request=='moved_p') then use='301 Moved'
when (request=='moved_p2') then use='200 OK'
when request='notimplemented' then use='501 Not implemented'
when (request=='notimpl') then use='501 Not implemented'
otherwise do
use='406 Not acceptable'
call pmprintf_sref('weird response '|| request||' '|| message)
end
end /* Add others to this list as needed */
select
when (request='redirect') | (request='moved_p') then do
parse var message method ':' rest
method = method':'
if (rest == '') | (pos('/', method) > 0) | (pos('\', method) > 0)then do
method = 'http:'
end
else message = rest
if (left(message,2) \= '//') then do
saddr = '//'ServerName
if (port \= 80) then saddr = saddr':'port
end
else saddr = ''
if (left(message,1) \= '/') then message = '/'message
message = method || saddr || message
'HEADER ADD URI: 'message
'HEADER ADD Location: 'message
doc = '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
end
when (request='moved_p2') then do
doc = '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'crlf,
"<html><head><title>URI has moved</title></head>"crlf,
"<body>"crlf,
message||crlf,
"<hr><em>HTTP response code:</em>" code crlf,
"<br><em>From server at:</em>" servername() crlf,
"</body></html>"
end
otherwise
nop
end
/* Now set the response and build the response file */
'RESPONSE HTTP/1.0' use /* Set HTTP response line */
parse var use code text
call lineout tempfile, '<!doctype html public "-//IETF//DTD HTML 2.0//EN">'
call lineout tempfile, "<html><head><title>"text"</title></head>"
call lineout tempfile, "<body><h2>Sorry...</h2>"
call lineout tempfile, "<p>The request from your Web client: " message"."
call lineout tempfile, "<hr><em>HTTP response code:</em>" code '['text']'
call lineout tempfile, "<br><em>From web server at:</em>" servername
call lineout tempfile, "<br><em>Running:</em>" server() ', ' sref_version()
call lineout tempfile, "</body></html>"
call lineout tempfile /* close */
'FILE ERASE TYPE text/html NAME' tempfile
EXIT -1
/* ----------------------------------------------------------------------- */
/* DOREDIRECT: do redirect for the URL if in dB, and logging */
/* ----------------------------------------------------------------------- */
DoRedirect: procedure expose sel servername port
parse arg RedirFile, RequestedFile
OK = 0
Case = 1
if (stream(RedirFile, 'c', 'query exists') \= '') then do
rc = stream( RedirFile, 'C', 'OPEN READ')
if (rc == 'READY:') then do until ((lines( RedirFile) == 0) | (OK))
WildCard = 0
do until (left(text,1) \= '!')
text = linein(RedirFile)
if (left(text,1) == '!') then do
if (translate( substr(text,2,14)) == 'CASE SENSITIVE') then Case = 0
end
end
parse var text old_sel':'new_sel rest
old_sel = strip(old_sel)
new_sel = strip(new_sel)
if (left(old_sel,1) == '/') then old_sel = substr( old_sel, 2)
if (pos('*', old_sel) > 0) then do
WildCard = 1
old_sel = left( old_sel, pos('*', old_sel)-1)
compare = left(sel, length(old_sel))
end
else compare = sel
if (Case) then do
Compare = translate( Compare)
old_sel = translate(old_sel)
end
if (compare == old_sel) then do
if (left(new_sel,5) == 'http:') then new_sel = substr(new_sel,6)
if (pos('*', new_sel) > 0) then do
new_sel = left( new_sel, pos('*', new_sel)-1)
if (WildCard) then new_sel = new_sel || substr( sel, length(old_sel)+1)
end
OK = 1
end
end
rc = stream(RedirFile, 'c', 'close')
end
if (OK=1) then do
if (pos( 'NOTIFY', translate(rest)) > 0) then do
crlf = '0d0a'x
doc = '<h2>This Resource has been Relocated.</h2>'crlf,
'<hr size=4>The file "'sel'" has been moved to:'crlf,
'"<A HREF="http:'new_sel'">http:'new_sel'</A>".<p>'crlf,
'Please make a note of the new URI, and update any references you can.<p>'
response('moved_p2', doc)
EXIT -1
end
else DO
response('moved_p', 'http:'new_sel)
EXIT -1
END
end
return 0