Discussion:
Age Old - Secure A .DBF On A File Server Question
(too old to reply)
Tim Cairns
2004-10-06 17:03:14 UTC
Permalink
What are my options if I want to protect my tables from outside access on a
file server (open, read, delete) other than through my application.

I know this is a loaded question with many possible solutions or partial
solutions. I'm looking for generalities and just need pointed in the right
direction, articles, web sites, third parties, etc.

These are tables with an associated .DBC.

VFP8, Microsoft NT Server or higher.

Thanks in advance.

Tim
Dan Freeman
2004-10-06 17:11:57 UTC
Permalink
About the only workable solution is filesystem security, which NT (and
later) handles nicely.

Of course, any user who needs to run your app will need to have access to
your data directory or your app will crash.

One option is to always use RUNAS when launching your app, and run it as the
only user with access to that directory. (Type RUNAS at any command prompt
to figure out how to do this.) This is only marginally secure, though,
because the user has access to the shortcut that will launch your app. But
it may be just the ticket for some cases.

Dan
Post by Tim Cairns
What are my options if I want to protect my tables from outside
access on a file server (open, read, delete) other than through my
application.
I know this is a loaded question with many possible solutions or
partial solutions. I'm looking for generalities and just need
pointed in the right direction, articles, web sites, third parties,
etc.
These are tables with an associated .DBC.
VFP8, Microsoft NT Server or higher.
Thanks in advance.
Tim
Paul Pedersen
2004-10-06 18:49:51 UTC
Permalink
Or encrypt the data.
Post by Dan Freeman
About the only workable solution is filesystem security, which NT (and
later) handles nicely.
Of course, any user who needs to run your app will need to have access to
your data directory or your app will crash.
One option is to always use RUNAS when launching your app, and run it as the
only user with access to that directory. (Type RUNAS at any command prompt
to figure out how to do this.) This is only marginally secure, though,
because the user has access to the shortcut that will launch your app. But
it may be just the ticket for some cases.
Dan
Post by Tim Cairns
What are my options if I want to protect my tables from outside
access on a file server (open, read, delete) other than through my
application.
I know this is a loaded question with many possible solutions or
partial solutions. I'm looking for generalities and just need
pointed in the right direction, articles, web sites, third parties,
etc.
These are tables with an associated .DBC.
VFP8, Microsoft NT Server or higher.
Thanks in advance.
Tim
Gary Brueggeman
2004-10-06 19:31:02 UTC
Permalink
On NT and 2000, a folder can be shared ending with a $. These folders are
'invisible' to Windows Explorer. You could create a folder with RWM rights
and refer to a table in your code as \\server\folder$\table. Can you use a
DBC? Few other applications can access this file structure.
Post by Paul Pedersen
Or encrypt the data.
Post by Dan Freeman
About the only workable solution is filesystem security, which NT (and
later) handles nicely.
Of course, any user who needs to run your app will need to have access to
your data directory or your app will crash.
One option is to always use RUNAS when launching your app, and run it as the
only user with access to that directory. (Type RUNAS at any command prompt
to figure out how to do this.) This is only marginally secure, though,
because the user has access to the shortcut that will launch your app. But
it may be just the ticket for some cases.
Dan
Post by Tim Cairns
What are my options if I want to protect my tables from outside
access on a file server (open, read, delete) other than through my
application.
I know this is a loaded question with many possible solutions or
partial solutions. I'm looking for generalities and just need
pointed in the right direction, articles, web sites, third parties,
etc.
These are tables with an associated .DBC.
VFP8, Microsoft NT Server or higher.
Thanks in advance.
Tim
Andrew Howell
2004-10-13 09:55:50 UTC
Permalink
Post by Gary Brueggeman
On NT and 2000, a folder can be shared ending with a $. These
folders are 'invisible' to Windows Explorer. You could create a
folder with RWM rights and refer to a table in your code as
\\server\folder$\table.
It's worth being aware that lots of other utilities can list the admin
shares.

--
Regards
Andrew Howell
Olaf Doschke
2004-10-13 10:41:29 UTC
Permalink
Post by Dan Freeman
One option is to always use RUNAS when launching your app, and run it as the
Besides RUNAS you could also use some API functions
to change the user account programmatic.

Here is some sample code:

*
* Impersonate.prg
*

#Define LOGON32_LOGON_INTERACTIVE 2
#Define LOGON32_LOGON_NETWORK 3
#Define LOGON32_LOGON_BATCH 4
#Define LOGON32_LOGON_SERVICE 5
#Define LOGON32_LOGON_UNLOCK 7
#Define LOGON32_LOGON_NETWORK_CLEARTEXT 8
#Define LOGON32_LOGON_NEW_CREDENTIALS 9

#Define LOGON32_PROVIDER_DEFAULT 0
#Define LOGON32_PROVIDER_WINNT35 1
#Define LOGON32_PROVIDER_WINNT40 2
#Define LOGON32_PROVIDER_WINNT50 3

Clear && Screen

someDeclarations()
Local lcNewUser, lcDomain, lcPassword, loLoginForm, loUserinfo

loUserinfo = CREATEOBJECT("custom")
Addproperty(loUserinfo,"cDomain","")
Addproperty(loUserinfo,"cNewUser","")
Addproperty(loUserinfo,"cPassword","")

loLoginForm = CREATEOBJECT("loginform",loUserinfo)
loLoginForm.show(1)
loLoginForm = .null.
RELEASE loLoginForm

lcDomain = loUserinfo.cDomain
lcNewUser = loUserinfo.cNewUser
lcPassword = loUserinfo.cPassword

RELEASE loUserinfo

Local lnSuccess, lnUserHandle, llTotalsuccess

* try Logon

* local Login (Domain = Computername):
lnSuccess = LogonUser( lcNewUser, lcDomain, lcPassword, ;
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, @lnUserHandle)

* See MSDN help on LogonUser for the meaning of the constants LOGON32,
* you may need to pass other values depending on Client and Server OS.

If lnSuccess>0
* impersonate user
lnSuccess = ImpersonateLoggedOnUser(lnUserHandle)
If lnSuccess>0
Local lcUserLoggedOn, lcName, lnBuffersize
lcName = Chr(0)
lnBuffersize = 64
lcUserLoggedOn = Replicate(lcName,lnBuffersize)

* this should be sufficient, to check if login succeeded:
? sys(0)

* alternative:
lnSuccess = WNetGetUser(@lcName, @lcUserLoggedOn, @lnBuffersize)
If lnSuccess = 0
lcUserLoggedOn = Chrtran(lcUserLoggedOn, Chr(0),"")

llTotalsuccess = (Upper(lcUserLoggedOn) == Upper(lcNewUser))
? "Login tried as " + lcNewUser
? "Logged in as: " + lcUserLoggedOn

If llTotalsuccess
DoSomethingAsLoggedInUser()
EndIf
Else
? "WNetGetUser failed with result:"+Transform(lnSuccess)
lastError()
Endif
Else
? "ImpersonateLoggedOnUser failed with result:"+Transform(lnSuccess)
lastError()
Endif
CloseHandle(lnUserHandle)
Else
? "LogonUser failed with result:"+Transform(lnSuccess)
lastError()
Endif

? Iif(llTotalsuccess,"Yessir!!","no luck this time")
RevertToSelf()
RETURN 0

Procedure someDeclarations()
Declare Short LogonUser In Win32API ;
String lcNewUserName, ;
String lcDomainName, ;
String lcPassword, ;
Integer lnLogonType, ;
Integer lnLogonProvider, ;
Integer @lnUserHandle

Declare Short ImpersonateLoggedOnUser In Win32API ;
Integer lnUserHanlde

Declare Integer WNetGetUser In Win32API ;
String @lcName, ;
String @lcUSer, ;
Integer @lnBuffersize

Declare Short RevertToSelf In Win32API

Declare Short CloseHandle In Win32API;
Integer lnHandle

Declare Long GetLastError In kernel32

Declare Integer FormatMessage In Win32API;
Integer dwFlags ,;
Integer lpvSource,;
Integer dwMsgId,;
Integer dwLangId,;
String @lpBuffer,;
Integer nSize,;
Integer Arguments

Declare Integer CreateProcessWithLogonW IN Advapi32;
String lpUsername,;
String lpDomain,;
String lpPassword,;
Integer dwLogonFlags,;
String lpAppName,;
String lpCmdLine,;
Integer dwCreationFlags,;
Integer lpEnvir,;
String lpCurDir,;
String @lpStartupInfo,;
String @lpProcessInfo

Endproc

Procedure lastError()
#Define FORMAT_MESSAGE_FROM_SYSTEM 8
#Define LANG_NEUTRAL 0

Local lnLastError
lnLastError = GetLastError()

Local lnSize, lcMessage
lcMessage = Replicate(Chr(0),2048)
lnSize = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,lnLastError,LANG_NEUTRAL,@lcMessage,Len(lcMessage)-1,0)
If lnSize > 2
lcMessage = Left(lcMessage,lnSize-2)
Else
lcMessage = ""
Endif
? "Error:" +Transform(lnLastError)+ " Message: "+lcMessage
Endproc

**************************************************
*-- Class: loginform (...\impersonate\libs\forms.vcx)
*-- ParentClass: form
*-- BaseClass: form
*-- Timestamp: 08/09/04 12:24:03 PM
*
DEFINE CLASS loginform AS form

AutoCenter = .t.
Top = 0
Left = 0
Height = 144
Width = 282
DoCreate = .T.
Caption = "Form"
Name = "loginform"


ADD OBJECT label1 AS label WITH ;
FontBold = .T., ;
Alignment = 1, ;
Caption = "User:", ;
Height = 17, ;
Left = 8, ;
Top = 12, ;
Width = 48, ;
Name = "Label1"


ADD OBJECT label2 AS label WITH ;
FontBold = .T., ;
Alignment = 1, ;
Caption = "Pass:", ;
Height = 17, ;
Left = 8, ;
Top = 44, ;
Width = 48, ;
Name = "Label2"


ADD OBJECT label3 AS label WITH ;
FontBold = .T., ;
Alignment = 1, ;
Caption = "Domain:", ;
Height = 17, ;
Left = 8, ;
Top = 76, ;
Width = 48, ;
Name = "Label3"


ADD OBJECT text1 AS textbox WITH ;
Height = 24, ;
Left = 61, ;
Top = 8, ;
Width = 211, ;
Name = "Text1"


ADD OBJECT text2 AS textbox WITH ;
Height = 23, ;
Left = 61, ;
Top = 40, ;
Width = 211, ;
PasswordChar = "*", ;
Name = "Text2"

ADD OBJECT text3 AS textbox WITH ;
Height = 23, ;
Left = 61, ;
Top = 72, ;
Width = 211, ;
Name = "Text3"


ADD OBJECT command1 AS commandbutton WITH ;
Default = .T., ;
Top = 104, ;
Left = 61, ;
Height = 27, ;
Width = 211, ;
Caption = "Login", ;
Name = "Command1"

PROCEDURE Init()
LPARAMETERS toUserinfo
This.AddProperty("oUserinfo",null)
This.oUserinfo = toUserinfo
ENDPROC

PROCEDURE command1.click()
thisform.oUserinfo.cNewUser = ALLTRIM(Thisform.text1.Value)
thisform.oUserinfo.cPassword = ALLTRIM(Thisform.text2.Value)
thisform.oUserinfo.cDomain = ALLTRIM(Thisform.text3.Value)

thisform.Release()
ENDPROC

ENDDEFINE
*
*-- EndDefine: loginform
**************************************************

Procedure DoSomethingAsLoggedInUser()
If lower(SUBSTR(SYS(0),AT(" # ",SYS(0))+3)) = "administrator"
? "You are administrator!"
Endif
Return
EndProc

But:
Try a SET STEP ON in the DoSomethingAsLoggedInUser() procedure
and type in some command. If foxcode.dbf is at default location you
won't be able to access it, and Intellisense will make problems. So you
should reconfigure at least the location of foxcode.dbf and perhaps some
more like foxuser.dbf, bacause these are normally configured for each
user within their own folders, and for switching user these should be
configured to public folders...

In principle now you can define an user account for the application
and give the appropriate rights only to this user. Of course then you
wouldn't diplay a login form for that user but the application would know
this username and password. Maybe store it encrypted within the exe.

Bye, Olaf.

Loading...