none
Passing AD/NTFS credentials via VBA RRS feed

  • Question

  • Is there any way to pass elevated credentials temporarily from within VBA to gain access to a folder to which the user running the Access application does not have rights?

    When using Access to store, index, and retrieve files such as .pdf or .tiff files, it is highly preferable to store them in a location to which the application, but not the user running the application, has access. Giving users direct access to folders containing indexed files is a recipe for chaos when the users find the files and decide to start adding, renaming, or deleting files--unbeknownst to the Access application that put the files there in the first place and is expecting them to be available for retrieval.

    We have multiple applications in which a user can browse for a file, attach it to a record, and then retrieve it at any time. But the process of attaching it is not to simply record the path where it is, because the user could put it there manually, and the user can just as easily delete it so that it is no longer accessible upon returning to the record. So instead, the attachment process copies the file to a different location reserved for these files, gives it an auto-numbered name, then records the full path/name in a field in the database. Retrieval, then is simply the opposite: go get the file.

    I am already managing file security pretty well by doing two things: 1) using hidden network shares so the top level of the network share cannot be found without explicitly knowing the share name and 2) granting users traverse-only rights a level above the folders where the files are stored. But, alas, in order to preserve the same path if we have to forklift the application and files to another server some day, we are using a mapped drive to the hidden share, which exposes the top-level folder to the users in Windows, despite the hidden share.

    Yes, the traverse-only right at that level means that the user would have to know the downline path to the file location in order to even get there. Still, it ultimately has to expose the storage location to the user running the application in order for that user to place or retrieve the files through the application. And that means there is always some risk of users' tinkering or malware intrusion to the storage folders.

    But I figured it cannot hurt to ask: is there a way to pass ActiveDirectory credentials temporarily in a VBA procedure so that I could use a folder to which the end user simply has no rights, but the account invoked to place/retrieve the folder does. This could all be embedded within the Access application where it would be transparent to the end user without all the need for tinkering at the NTFS level.


    Thursday, October 3, 2019 2:31 PM

All replies

  • No. All VBA code runs under the security context of the logged in user.

    You would have to start another Process using different credentials, using some API calls.


    -Tom. Microsoft Access MVP

    Thursday, October 3, 2019 4:11 PM
  • Well, I am not afraid of spawning a separate process. If I understand your response correctly, Tom, then I could perhaps use the CreateProcessWithLogonW or CreateProcessAsUser API call, passing elevated credentials, to open XCopy.exe or RoboCopy.exe coupled with the command-line arguments to copy the file from the source path to a secured location.

    Would it be possible to open a separate process and then hand it the CopyFile Windows API call, or does the alternate-credential application have to contain the Windows API call within it?

    Does that sound close to correct? If so, do you have any code samples so I do not have to start from scratch? Windows API calls are not my forte, and although I have used many of them in VBA, they have always been by finding relevant VBA code snippets someone has posted.

    And do you know if UAC will complain about attempting to elevate a process using credentials that differ from the current user?

    Thursday, October 3, 2019 6:55 PM
  • Sorry, I have nothing I can share.

    Maybe I would just run cmd.exe /c xcopy fromhere tothere


    -Tom. Microsoft Access MVP

    Friday, October 4, 2019 12:31 AM
  • We have multiple applications in which a user can browse for a file, attach it to a record, and then retrieve it at any time. But the process of attaching it is not to simply record the path where it is, because the user could put it there manually, and the user can just as easily delete it so that it is no longer accessible upon returning to the record. So instead, the attachment process copies the file to a different location reserved for these files, gives it an auto-numbered name, then records the full path/name in a field in the database. Retrieval, then is simply the opposite: go get the file.

    Hi Brian,

    I have an application with a different functionality, but with many parallels.

    All files have a record in a File_tbl, resulting in an unique File_id (Autonumber) per file. These File_id's can be coupled to a "Documentation" record. The fields in the File_tbl are: File_id, Filename, Filepath, other file attributes.

    The user can place new files in his own user-map. With a button on the File_form it is easy to synchronize the files in the File_tbl with the files in the user-map, using the field Filepath.

    From time to time an authorized person/process can move the files from the user-map(s) to a protected-map, to "freeze" the files.

    Users only "see" the files through the File_form. If necessary they can open the file for further inspection. The Filepath control is hidden for non-authorized users.

    After changing the Filename control in the File_form, the corresponding name of the file in the user-map or protected-map is also changed. The same holds for the Filepath (only by authorized users): changing it moves the file from the old Filepath to the new Filepath.

    Users don't see any maps. Because of more file attributes in the File_tbl they can make a faster and better choice which files to couple.

    Perhaps it gives you some ideas.

    Imb.

    Friday, October 4, 2019 7:51 AM
  • Imb-hb,

    My question is not how manage moving files or how to make the file path not obvious to the user; we already do all of that.

    The question is how to actually prevent the user from having NTFS rights to the folder where the files go so that they cannot access files directly in Windows Explorer. So long as the user has access to the files' location through Windows, there is some risk of users getting into the folders and moving or deleting files--even if that path is not obvious through the Access application.

    How do you 1) prevent users from having access to the file location while at the same time 2) allowing them to put files there via Access code?

    We cannot use a file copy process at a separate time by a different user because that would change the file's path to be something different from what is recorded in the database record.

    Friday, October 4, 2019 3:16 PM
  • How do you 1) prevent users from having access to the file location while at the same time 2) allowing them to put files there via Access code?

    We cannot use a file copy process at a separate time by a different user because that would change the file's path to be something different from what is recorded in the database record.

    Hi Brian,

    Probably you interpreted my answer in a different way than I meant.

    Users place new files in a "free" user-map. A simple press on a button synchronize the files in the user-map with the database. That is, new files are entered in the database: the FileName and FilePath are stored, and the file gets its unique File_id. From then on these files can be coupled to other records, using there File_id.

    From time to time an authorized person moves the files from the user-map to the protected-map, just by modifying the FilePath in the database. As you know, the AfterUpdate event of FilePath takes care of that. From then the file is "frozen", but still have the same File_id: so nothing changes in the rest of the database.

    I hope it is clear now.

    Imb.

    Friday, October 4, 2019 5:51 PM
  • I do understand. It just does not address the issue: I need to prevent users from having any direct NTFS access to the file location except through the application.

    In your scenario, if the files are moved to a "frozen" location (i.e. presumably one to which the end user does not have access), how would the end user (not the "authorized person") access them? My need is for end users to store and retrieve the files without being able to access that file path directly in Windows Explorer, and this would, I think, require passing elevated credentials to a Windows API when placing or retrieving the files.

    Friday, October 4, 2019 5:58 PM
  • I need to prevent users from having any direct NTFS access to the file location except through the application.

    Hi Brian,

    In my view the users never see the PathName to the file. In the application the full file specification is constructed from the (hidden) FilePath and the visible FileName. If necessary, a "frozen" file can first be copied to a neutral user-map to prevent the user to see the full file specification when opening/reading the file. The PathName contains an "only pass-through" map.

    Imb.

    Friday, October 4, 2019 6:36 PM
  • But again, the question is not whether the user can see the particular path in the application. That just ensures that the user cannot tell where the file is;  it does not actually prevent that user, or any other, from getting into that folder--intentionally or otherwise, and even without knowing it is related to this application--and renaming or deleting files in Windows Explorer.

    That, of necessity, involves storing files in an NTFS location not accessible to--not simply out of sight of--the user running the application. And it follows that this would require passing elevated credentials to a process that actually stores and retrieves the files from that location.

    Friday, October 4, 2019 6:45 PM
  • it does not actually prevent that user, or any other, from getting into that folder--intentionally or otherwise, and even without knowing it is related to this application--and renaming or deleting files in Windows Explorer.

    Hi Brian,

    I see your point now, I have no experience in that direction. In my application the hiding of the PathName was "enough".

    Success with your further search.

    Imb.

    Friday, October 4, 2019 6:57 PM
  • Thank you. Part of my problem is that I manage networks, so I tend to see risks that many developers do not. It's a blessing...and a curse...
    Friday, October 4, 2019 7:01 PM
  • I'm not an Access user so this is just a bit of brainstorming that I hope will be helpful.

    First, I don't see why elevated credentials are necessary.  You don't want the interactive user to have access to the folder on a network share.  It seems to me that what you might be able to do is to use impersonation when performing the network access so that the shared folder is accessed using an account that is allowed access and which is different from that of the interactive user.

    See LogonUser and the LOGON32_LOGON_NEW_CREDENTIALS parameter.

    Also see ImpersonateLoggedOnUser.

    I'm guessing that your Access VBA code could use these two Windows API functions to obtain and use the access token for an account that has access to the network share.  Of course your application would need to include security measures to assure the integrity of the credentials used in the call to LogonUser.
    Friday, October 4, 2019 8:56 PM
  • RLWA32: I think this is what I have been looking for. By "elevated credentials", I am not looking to elevate the current user outside the context of the specific file save/open action. Maybe Impersonation is what this is all actually called.

    I will find out by testing whether the LogonUser will work, since 1) it has to happen while a user is already logged onto the computer (not sure if LogonUser will try to preempt that) and 2) I do not necessarily want the baggage of having a logon event hit AD every time I do this.

    Then again, I am not certain that ImpersonateLoggedOnUser will work without first logging on a user--that could potentially preempt the currently logged-on user.

    I suspect that the CreateProcessWithLogonW or CreateProcessAsUser API calls might be what I am looking for here.

    Friday, October 4, 2019 9:10 PM
  • If you read the description for LOGON32_LOGON_NEW_CREDENTIALS you will note that it clones the token of the current user and the credentials associated with the logon are only used for outbound network access.  My experience has been that when this parameter is passed to LogonUser that the credentials associated with network access are authenticated by the server during network access and are not authenticated at the client at the time that LogonUser is called.

    Since the token of the current user is cloned, ImpersonateLoggedOnUser with that token would have no effect on the client system since, for non-network operations, the process token and the thread token would be for the same user -- the interactive user that logged-on.

    I'm sorry that I didn't explicitly point out that the current user token was cloned and that my prior description was badly worded.

    I'd be interested in the results of your test.




    • Edited by RLWA32 Friday, October 4, 2019 10:35 PM
    Friday, October 4, 2019 10:30 PM