-
September 7th, 2002, 11:28 PM
#1
Web based IIS administration (ADSI)
Overview
Sorry I've not been around for a while boys and girls - but what with holidays (mine and staffs) etc I have been a busy bunny over the last few months (the bit that wasn't spent in Bali anyway ). So just to make ammends here's a web class I've been writing for web based IIS Webserver administration class that some of you might find interesting.
If you want to use the class then download the attached iiscls.inc file rather than cutting and pasting the code below - I've cut it up some to get it to fit on the page.
NOTE: This script has to be run from an admin account.
Usage
**This class exposes the following properties
TraceOn - Boolean.
Set Trace on = true if you require debug info sent to the response object
ie. on screen at runtime. Logging information can also be retreived using the GetTrace Function
ServerName - String
Name of server to perform operation on
**This class exposes the following methods:
GetTrace - Returns Array of log items in : delimited format
DenyIP(svc,ip,subnet) - Add an IP to the deny list for site (Returns Boolean)
NOTE: This implicitly sets IPAllow to Allow by default with exclusions.
svc - service tag
ip - IP to deny eg 127.0.0.1
Subnet - Subnet of ip to deny eg 255.255.255.255
Example usage:
BOOL = denyip 7,"111.111.111.111","255.255.255.255"
AppDebug(svc,booldbg, message) - Set the send detailed error messages property for service (Returns Boolean)
svc - service tag
booldbg - Boolean set to true if debug is on
message - Message to display if booldbg is false
Example usage:
BOOL = appdebug 5,false,errmess - App Debug off
BOOL = appdebug 5,TRUE,"" - App Debug on
AppCreate(svc,frname,isolation) - Creates an IIS Application for the service (Returns Boolean)
svc - service tag
frname - Friendly name (descriptive)
isolation - Application Protection (low - IIS process=0 / medium - pooled=2 / high - isolated=1)
Example usage:
BOOL = appcreate 7,"www.whatever.com",0
MakeSite(IPAddress , PortNum, HostName, RootDirectory) - Creates a new site (Returns service tag or -1 for fail)
IPAddress - IP Address of new service eg 127.0.0.1
PortNum - Port number of new service eg 80
HostName - Host name of new service eg www.whatever.com
RootDirectory - Physical path to root of new service eg c:\webs\sitepath
Example usage:
makesite("127.0.0.1", "80", "www.whatever.com", "c:\webs\sitepath")
DeleteSite(svc) (Returns Boolean)
BOOL = svc - service tag
AddBinding(svc,IpAddress,PortNum,HostName) Add a binding to the specified service (Returns Boolean)
svc - service tag
IpAddress - IP Address of new binding eg 127.0.0.1
PortNum - Port Number of new binding eg 80
HostName - Host Name of new binding eg www.whatever.com
Example usage:
BOOL = AddBinding(160,"195.8.181.206","80","www.123atestsite.co.uk")
BindingsList(svc) - Returns Array of bindings in : delimited format eg svc:IPort:host
svc - filter list by a specific service tag or "" for all
IIBackup(bkupName) - Backup the metabase to $winnt$\system32\inetsvr\metaback\bkupName (boolean)
bkupName - Filename of backup
Sample ASP code
Code:
<%
'Create instance of IIS Cls
Set iis = NEW iiscls
'Set traceon (Boolean) for runtime debug
iis.traceon = false
'Set IIS server to localhost
iis.servername = "localhost"
main
WriteDebug
Sub Main
'***********************************
'**Make the new site
newsvc = iis.makesite("127.0.0.1", "80", "www.atestsite.co.uk", "c:\webs\path")
'If the makesite function fails (-1) the quit
if newsvc = -1 then exit sub
'***********************************
'**Create an application for our new site
If not iis.appcreate(newsvc,HostName,0) then exit sub
'***********************************
'**Set the debug message of our new site
if not iis.AppDebug(newsvc,false, errmess) then exit sub
'***********************************
'**Add a binding to the selected site
if not iis.AddBinding(newsvc,"127.0.0.1","80", & _
"www.123atestsite.co.uk") then exit sub
'***********************************
'**list bindings on new service
bind = iis.bindingsList(newsvc)
for n = 1 to ubound(bind)
response.write bind(n) & "
"
next
'***********************************
'**Deny IP from site
if not iis.denyip(newsvc,"111.111.111.111", & _
"255.255.255.255") then exit sub
'***********************************
'**Remove binding from service
if not iis.RemoveBinding(newsvc,"1270.0.1","80", & _
"www.123atestsite.co.uk") then exit sub
'***********************************
'**Delete the site we created
if not iis.deletesite(newsvc) then exit sub
'***********************************
'**List all services
bind = iis.bindingsList("")
for n = 1 to ubound(bind)
response.write bind(n) & "
"
next
'***********************************
'**Back up metabase
response.write "<h2>" & "Back up metabase" & "</h2>"
iis.iibackup("Backupname.md0")
end sub
sub WriteDebug
response.write "<h1>Debug Log</h1>"
response.write "<table border = '1'>"
col = iis.GetTrace
for y = 0 to ubound(col)
response.write "<tr>"
row = split(col(y),"|")
for x = 0 to ubound(row)
response.write "<td>" & row(x) & "</td>"
next
response.write "</tr>"
next
response.write "</table>"
end sub
The IIS Class File
Code:
<%
'IISCls by ntsa
'6/11/2002
'www.ntsa.org.uk
ary_err = array
Private m_TraceOn
Private m_ServerName
Const MD_BACKUP_SAVE_FIRST = 2 'Backup
Const MD_BACKUP_FORCE_BACKUP = 4 'Backup
Const MD_BACKUP_NEXT_VERSION = &HFFFFFFFF 'Backup
Class IISCls
'______________________________________________
'The code!
'**Public properties
Public Property Let TraceOn(str_TraceOn)
m_TraceOn = str_TraceOn
End Property
Public Property Let ServerName(str_ServerName)
m_ServerName = str_ServerName
End Property
'**Private Subs
private sub trace(data)
if m_TraceOn = true then response.write "iiscls.inc|" & _
data & "
"
'Add data to log
redim preserve ary_err(ubound(ary_err)+1)
ary_err(ubound(ary_err)) = "iiscls.inc|" & data
end sub
'***Private Functions
private function NextSite
on error resume next
index = 0
do
Index = Index + 1
Set SiteObj = GetObject("IIS://" & _
m_ServerName&"/w3svc/" & Index)
' A web server is already defined at
'this position so increment
loop until Err.Number <> 0 or index = 10000
'Sanity checking
trace "NextSite|Validating new index"
if index < 10000 then
'Make sure the error corresponds with site not '
found error code
if err.number = -2147024893 then
'Error is ok (arse about face though it sounds!)
trace "NextSite|Validated ok. Availible Site found at " & index
err.clear
nextsite = index
ELSE
trace "NextSite|An unexpected error occured " & _
"opening service IIS://"&m_ServerName&"/w3svc/" & Index
trace "NextSite|Error: " & err.description
nextsite = -1
end if
else
'Sanity has been lost!
trace "NextSite|No sites availible (Oh ****!)"
nextsite = -1
end if
end function
private function DuplicateBinding(IpAddress,PortNum,HostName)
trace "DuplicateBinding|Ensuring Binding ("&IpAddress & ":" &_
PortNum & ":" & HostName&") is unique"
BindingString = IpAddress & ":" & PortNum & ":" & HostName
DuplicateBinding = false
on error resume next
'Get the webserver object
Set w3svc = GetObject("IIS://" & m_ServerName & "/w3svc")
'If the webserver loaded ok
If Err.Number = 0 Then
'Iterate through the websites
For Each WebServer in w3svc
'If the class of the current object is a webserver
If WebServer.Class = "IIsWebServer" Then
'Load the bindings
Bindings = WebServer.ServerBindings
for n = 0 to ubound(Bindings)
if trim(cstr(Bindings(n))) = trim(cstr)BindingString)) then
trace "DuplicateBinding|Found duplicate binding!"
DuplicateBinding = true
exit function
end if
next
End If
Next
else
trace "DuplicateBinding|Error opening " & _
"IIS://" & m_ServerName & "/w3svc - " & err.description
end if
end function
'***Public Functions
Public Function DenyIP(svc,ip,subnet)
on error resume next
dnip = ip & ", " & subnet
trace "DenyIP|Opening service w3svc/" & svc & " security settings"
Set oService = GetObject("IIS://"& m_ServerName &"/W3SVC")
Set oServer = oService.GetObject("IIsWebServer", svc)
Set oVDir = oServer.GetObject("IIsWebVirtualDir", "ROOT")
Set oIPSecurity = oVDir.IPSecurity
if err.number <> 0 then
trace "DenyIP|Could not open service w3svc/" & svc & " security settings"
trace "DenyIP|Error: " & err.description
DenyIP = false
exit function
else
trace "DenyIP|Opened w3svc/" & svc & " security settings"
'Set Grant by Default to true if set otherwise
'NOTE: setting a deny list implicitly calls grant by default.
trace "DenyIP|Checking GrantByDefault is TRUE"
if oIPSecurity.GrantByDefault = false then
trace "DenyIP|GrantByDefault is FALSE - Setting to TRUE"
oIPSecurity.GrantByDefault = true
else
trace "DenyIP|GrantByDefault is already TRUE"
end if
trace "DenyIP|Loading Deny list array"
dIPs = oIPSecurity.IPDeny
trace "DenyIP|Checking the IP/Subnet is not duplicated"
'Check the IP/Subnet is not duplicated
'**TASK - ignore requests within same subnet.
'**eg adding '192.168.0.1,255.255.255.0' would subsequently proclude
'**adding '192.168.0.2,255.255.255.255' because the second is already
'**disallowed by the first - NOT required for current project.
dup = false
for n = lbound(dips) to ubound(dips)
if trim(cstr(dips(n))) = trim(cstr(dnip)) then
dup = true
denyIP = false
trace "DenyIP|This IP/Subnet already exists!"
exit function
end if
next
'If no duplicate then add new IP to array
if dup = false then
trace "DenyIP|IP is good so add it to the Deny Array"
redim preserve dips(ubound(dips)+1)
dips(ubound(dips)) = dnip
oIPSecurity.IPDeny = dips
'Write array back to metabase
trace "DenyIP|Write array back to metabase"
oVDir.IPSecurity = oIPSecurity
'Save metabase
trace "DenyIP|Save metabase"
oVDir.SetInfo
end if
if err.number <> 0 then
trace "DenyIP|Saving new security info failed"
trace "DenyIP|Error: " & err.description
DenyIP = false
else
trace "DenyIP|Saved new security info"
denyIP = true
end if
end if
End Function
Public Function AppDebug(svc,booldbg, message)
AppDebug = false
on error resume next
trace "AppDebug|Opening service w3svc/" & svc & " application settings"
Set oService = GetObject("IIS://"& m_ServerName &"/W3SVC")
Set oServer = oService.GetObject("IIsWebServer", svc)
Set oVDir = oServer.GetObject("IIsWebVirtualDir", "ROOT")
if err.number <> 0 then
trace "AppDebug|Could not open service w3svc/" & svc & _
" application settings"
trace "AppDebug|Error: " & err.description
AppDebug = false
exit function
end if
oVDir.AspScriptErrorSentToBrowser = booldbg
trace "AppDebug|Debug is currently set to " & booldbg
if booldbg = false and len(message) > 0 then
trace "AppDebug|Setting Error message"
trace "AppDebug|Error: " & err.description
oVDir.AspScriptErrorMessage = message
end if
trace "AppDebug|Saving metabase"
' Write info back to Metabase
oVDir.SetInfo
if err.number <> 0 then
trace "AppDebug|Could not save service w3svc/" & svc & _
" application settings"
trace "AppDebug|Error: " & err.description
AppDebug = false
exit function
else
'It all worked!
AppDebug = true
end if
End Function
Public Function AppCreate(svc,frname,isolation)
on error resume next
trace "AppCreate|Creating application for service w3svc/" & svc
Set oService = GetObject("IIS://"& m_ServerName &"/W3SVC")
Set oServer = oService.GetObject("IIsWebServer", svc)
Set oVDir = oServer.GetObject("IIsWebVirtualDir", "ROOT")
if err.number <> 0 then
trace "AppCreate|Could not open service w3svc/" & svc & _
" security settings"
trace "AppCreate|Error: " & err.description
AppCreate = false
exit function
end if
trace "AppCreate|Setting service w3svc/" & svc & " security settings"
oVDir.AppCreate True
' Application Name
oVDir.AppFriendlyName = frname
' Application Protection
'(low - IIS process=0 / medium - pooled=2 / high - isolated=1)
oVDir.AppIsolated = isolation
oVDir.SetInfo
trace "AppCreate|Saving metabase"
if err.number <> 0 then
trace "AppCreate|Could not save service w3svc/" & svc & _
" security settings"
trace "AppCreate|Error: " & err.description
AppCreate = false
exit function
else
AppCreate = true
end if
End Function
Public function GetTrace
'response.write "getting trace on " & ubound(ary_err) & " items.
"
'for n = 1 to ubound(ary_err)
' response.write ary_err(n)
'next
GetTrace = ary_err
End function
Public function MakeSite(IPAddress , PortNum, HostName, RootDirectory)
makesite = -1
on error resume next
'If the specified binding does not already exist
if not DuplicateBinding(IPAddress,PortNum,HostName) then
index = nextsite
'Make sure index is not -1
if index = -1 then
trace "MakeSite|Failed to find next availible site"
trace "MakeSite|Quiting"
exit function
end if
'Index is ok
Set w3svc = GetObject("IIS://" & m_ServerName & "/w3svc")
Set NewWebServer = w3svc.Create("IIsWebServer", cint(Index))
If (Err.Number <> 0) Then
' If call to Create failed then return fail
TRACE "MakeSite|Failed to create site at index " & index
TRACE "MakeSite|error # " & err.number & " - " & err.description
MakeSite = -1
Else
'Site created
MakeSite = index
trace "MakeSite|A new site has been created with service tag " & index
NewBindings = Array(0)
NewBindings(0) = IpAddress & ":" & PortNum & ":" & HostName
trace "MakeSite|Adding bindings " & IpAddress & _
":" & PortNum & ":" & HostName
NewWebServer.ServerBindings = NewBindings
trace "MakeSite|Setting server comment"
NewWebServer.ServerComment = HostName
' NewWebServer.KeyType = "IIsWebServer"
trace "MakeSite|Saving bindings to metabse"
NewWebServer.SetInfo
' Now create the root directory object.
trace "MakeSite|Setting root directory to: '"& rootdirectory &"'"
Set NewDir = NewWebServer.Create("IIsWebVirtualDir", "ROOT")
NewDir.Path = RootDirectory
NewDir.AccessRead = true
Err.Clear
trace "MakeSite|Saving root directory Info"
NewDir.SetInfo
'Attempting to start new web server..."
trace "MakeSite|Attempting to start the new service..."
Err.Clear
Set NewWebServer = GetObject("IIS://" & m_ServerName & "/w3svc/" & _
Index)
NewWebServer.Start
if err.number <> 0 then
trace "MakeSite|Could not start server IIS://" & m_ServerName & _
"/w3svc/" & Index
trace "MakeSite|" & err.description
else
trace "MakeSite|Server started sucsessfully"
end if
end if
else
'The Binding already exists!
Trace "MakeSite|The binding specified alredy exists!"
MakeSite = -1
end if
on error goto 0
end function
Public function DeleteSite(svc)
on error resume next
Trace "DeleteSite|Deleting service w3svc/" & svc
Dim WebServiceObj
'Get the Web service object, which contains servers.
Set WebServiceObj = GetObject("IIS://"& m_ServerName &"/W3SVC")
if err.number <> 0 then
trace "DeleteSite|Could not open IIS://"& m_ServerName &"/w3svc"
DeleteSite = false
Exit Function
end if
'Delete specified service
WebServiceObj.Delete "IIsWebServer", cstr(svc)
if err.number = 0 then
Deletesite = true
Trace "DeleteSite|Service w3svc/" & svc & " deleted"
else
deletesite = false
Trace "DeleteSite|Could not delete service w3svc/" & svc
trace "DeleteSite|Error: " & err.description
end if
end function
Public function AddBinding(svc,IpAddress,PortNum,HostName)
on error resume next
DIM sbind
trace "AddBinding|Opening bindings for site w3svc/" & svc
Set obj = GetObject("IIS://"& m_ServerName &"/w3svc/" & svc)
servbind = Obj.Get("serverbindings")
if err.number <> 0 then
trace "AddBinding|Could not open service IIS://"& m_ServerName &"/w3svc/" & svc
trace "AddBinding|Error: " & err.description
addbinding = false
Exit Function
else
trace "AddBinding|Opened service IIS://"& m_ServerName &"/w3svc/" & svc
if not DuplicateBinding(IpAddress,PortNum,HostName) then
addbinding = true
REDIM preserve servbind(ubound(servbind) +1)
'Add new binding to Array
servbind(ubound(servbind)) = IpAddress & ":" & PortNum & ":" & HostName
'Write server bindings back to metabase
Obj.Put "serverbindings", servbind
'Save Metabase
obj.setinfo
trace "AddBinding|Saving to metabase"
else
addbinding = false
trace "AddBinding|Add binding failed"
end if
end if
end function
Public function RemoveBinding(svc,IpAddress,PortNum,HostName)
on error resume next
DIM sbind
RemoveBinding = false 'Flag to show if delete is ok
trace "RemoveBinding|Opening bindings for site w3svc/" & svc
Set obj = GetObject("IIS://"& m_ServerName &"/w3svc/" & svc)
servbind = Obj.Get("serverbindings")
if err.number <> 0 then
trace "RemoveBinding|Could not open service IIS://"& m_ServerName & _
"/w3svc/" & svc
trace "RemoveBinding|Error: " & err.description
RemoveBinding = false
Exit Function
else
trace "RemoveBinding|Opened service IIS://"& m_ServerName &"/w3svc/" & svc
trace "RemoveBinding|Searching for binding (" & IpAddress & ":" & PortNum & &
":" & HostName & ")..."
bind = array
'iterate through binding for service tag
for n = 0 to ubound(servbind)
b = split(servbind(n),":")
'Check to see if this is binding to delete
if IpAddress = b(0) and PortNum = b(1) and HostName = b(2) then
'Found Binding
trace "RemoveBinding|Found binding - Binding #" & n & _
" (" & servbind(n) & ") "
trace "RemoveBinding|Remove binding sucsessful"
RemoveBinding = true
else
trace "RemoveBinding|No Match - Binding #" & n & _
" (" & servbind(n) & ")"
'Binding is not deleted
'Create new value in the array
redim preserve bind(ubound(bind)+1)
bind(ubound(bind)) = servbind(n)
end if
next
if RemoveBinding = true then
trace "RemoveBinding|Saving changes to metabase"
'Writing new bindings
Obj.Put "serverbindings", Bind
'Save Metabase
obj.setinfo
'Sanity check
if err.number <> 0 then
trace "RemoveBinding|Could not remove w3svc object IIS://" & _
m_ServerName & "/w3svc/" & svc
trace "RemoveBinding|Error: " & err.description
exit function
end if
else
'Nothing to remove
trace "RemoveBinding|Binding (" & IpAddress & ":" & PortNum & _
":" & HostName & ") not found on object IIS://" & m_ServerName & _
"/w3svc/" & svc
end if
end if
end function
Public function BindingsList(svc)
on error resume next
trace "BindingsList|Listing Bindings"
dim bind
redim bind(0)
if len(svc) > 0 then
'A filter has been selected
trace "BindingsList|List filtered by service tag " & svc
trace "BindingsList|Opening w3svc object IIS://" & m_ServerName & _
"/w3svc/" & svc
Set obj = GetObject("IIS://"& m_ServerName &"/w3svc/" & svc)
servbind = Obj.Get("serverbindings")
if err.number <> 0 then
trace "BindingsList|Open failed for w3svc object IIS://" & m_ServerName & _
"/w3svc/" & svc
trace "BindingsList|Error: " & err.description
exit function
end if
for n = 0 to ubound(servbind)
redim preserve bind(ubound(bind)+1)
bind(ubound(bind)) = svc & ":" & servbind(n)
next
else
'No filter has been selected - list all
trace "BindingsList|Opening w3svc object IIS://" & m_ServerName & "/w3svc"
Set w3svc = GetObject("IIS://" & m_ServerName & "/w3svc")
'If the webserver loaded ok
If Err.Number = 0 Then
trace "BindingsList|Opened IIS://" & m_ServerName & "/w3svc object"
'Iterate through the websites
For Each WebServer in w3svc
'If the class of the current object is a webserver
If WebServer.Class = "IIsWebServer" Then
'Load the bindings
Bindings = WebServer.ServerBindings
for n = 0 to ubound(Bindings)
redim preserve bind(ubound(bind)+1)
bind(ubound(bind)) = WebServer.name & _
":" & Bindings(n)
next
End If
Next
else
trace "BindingsList|Error opening " & "IIS://" & m_ServerName & _
"/w3svc" & " - " & err.description
end if
end if
BindingsList = bind
end function
function IIBackup(bkupName)
Dim ComputerObj, iFlags
IIBackup = true
'on error resume next
trace "Backup|Loading IIS://"& m_ServerName
'Load the specified server
Set ComputerObj = GetObject("IIS://" & m_ServerName)
if err.number <> 0 then
trace "Backup|Could not open IIS://"& m_ServerName
trace "Backup|Error: " & err.description
IIBackup = false
exit function
end if
trace "Backup|Loaded IIS://"& m_ServerName & " Ok"
trace "Backup|Backing up metabase to file: " & bkupName
'Make a backup of the metabase to filename bkupName
iFlags = (MD_BACKUP_SAVE_FIRST or MD_BACKUP_FORCE_BACKUP)
ComputerObj.Backup bkupName, MD_BACKUP_NEXT_VERSION, iFlags
if err.number <> 0 then
trace "Backup|Backup of IIS://"& m_ServerName & " failed"
trace "Backup|Error: " & err.description
IIBackup = false
exit function
end if
trace "Backup|Backup of IIS://"& m_ServerName & " ok"
end function
end class
%>
If you enjoyed this then have a look at these:
Cloaked Exploit Scanner Part I and Part II
Google 'exploit' - TCPUtil pt III
Open Source FTP Control
Ending Corporate SPAM
Web based classes
Backing up the IIS metabase.
What port is that?
Building your own IDS tripwire.
Credit card security
Dumping SQL data to a text file
Hunting down skript kiddies
Search Engine submission 'exploit'
Forced shutdown of a remote nt/2k server
Securing an installation of IIS 4. (No, seriously)
Remote DSN Connections, using WinAPIs and the registry
Scripting Internet Connections Under Window$
\"I may not agree with what you say, but I will defend to the death your right to say it.\"
Sir Winston Churchill.
-
September 7th, 2002, 11:30 PM
#2
Awesome tutorial, as expected from NTSA. Of course, Im more into apache but hey :P. Anyways, nice job man! -- Jason Copeland
-
September 8th, 2002, 04:15 AM
#3
Thats cool, love your tutorials. Even when I wasn't a member I would read them. Great tutorial, very informative and useful. Got 2 questions though.
1. What version of IIS is this?
2. Would any of your IIS tutorials work for PWS? I know the secure IIS one would, but how about others?
-
September 8th, 2002, 06:12 AM
#4
NTSA glad the Holiday was good for you, as always your info and tuts are excellent and I view them with respect. I do have a question though and it has to do with teaching and knowledge. Yes it is true none of these things should be held away but what value is there in teaching any student not knowing how they will use what they learn? I am asking because I am a father of 3 sons and I pass to them things they need to know at the right age and they are mature enough to fully understand what the knowledge is about (that is called wisdom). After all I see a mad man given information and he in turn and a few of his buddies caused 9-11. I mean no disrespect to you admire your tuts but ask my question Peace
I believe that one of the characteristics of the human race - possibly the one that is primarily responsible for its course of evolution - is that it has grown by creatively responding to failure.- Glen Seaborg
-
September 8th, 2002, 08:42 AM
#5
linuxelite -
1. IIS 4 and up
2. Errrm...Probably? I don't use PWS, even for staging, so I'm guessing. If PWS supports multiple server bindings and ADSI then this should work. Check your docs for references to ADSI.
Palemoon -
what value is there in teaching any student not knowing how they will use what they learn?
I just feel that it is important to publish as much of my work as I can get away with on sites such as this where they may be useful to someone. I am not a teacher by proffession and so I don't expend large quantities of effort in understanding the vauguaries of that process. I just figure that if I needed a bit of code someone else probably will too.
And if my code saves that someone else the endless web-crawls and MSDN searches that I underwent to write the code in the first place then that someone else may use the time to write something else which they might also publish.
On AO my 'good' articles reach about 500 views. Say just 10% of viewers find it useful and write something else in the time they saved. Thats another 50 published code exerpts. The worldwide knowledge base expands just a little further, and next time I am stuck I might just run across one of those 50 articles that is useful to me.
If that doesn't answer the question then please rephrase.
\"I may not agree with what you say, but I will defend to the death your right to say it.\"
Sir Winston Churchill.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
|