Accessing a .NET Assembly from classic ASP - c#

I have been trying to access a .NET Assembly that I have created in classic ASP using
dim foo
set foo = Server.CreateObject("TestAssembly.MyClass")
The problem is I'm getting an error:
Server object error 'ASP 0177 : 800401f3'
Server.CreateObject Failed
/test.asp, line 4
Invalid class string
I have registered the assembly (TestAssembly.dll) using gacutil and regasm as instructed in the article: Replacing Old Classic ASP COM Components with .NET Assemblies which I referenced from another question. It supplies two methods in which to install the assembly and I have tried both, but to no avail.
Getting this working would be great because it would allow me to gradually migrate a classic ASP site to .NET

Another thing to check: make sure your .Net assembly is set to be COM Visible.

Check in the registry here: *HKLM\SOFTWARE\Classes* and see if the namespace.class is there (e.g. "TestAssembly.MyClass") and that it has a key called "CLSID" with a valid ID.
If the registry entry isn't there then make sure that Project > Properties > Assembly Information has "Make assembly COM-Visible", then recompile.
Once compiled, run regasm (if you're on a 64bit machine they you will have to explicitly reference the 64bit version of regasm - c:\Windows\microsoft.net\framework64\v4.0.30319\regasm) with:
regasm /codebase /tlb TestAssembly.dll

This error means "Invalid class string" -- in other words the call to CreateObject failed because the name object cannot be found by the OLE sub-system. Causes include:
You really didn't run regsvr32 on the server after all.
You ran regsvr32 but it reported an error.
Someone modified security on part of the registry that's preventing the OLE subsystem from reading all or part of the HKEY_CLASSES_ROOT tree.
The name of the object you are trying to create was mispelled or is incorrect.
Determine if it's a permissions problem
Add the anonymous user (used by IIS) to the Administrators group. The test page then worked, proving it was a permissions problem. Do not forget to remove the anonymous IIS user from the Admin group!
Determine if it is a file permissions problem:
After removing the Anonymous user from the Admin group, add failure auditing to the file (smtpsvg.dll), which will determine if the file was ever accessed (by the lack of the failure event). If it isn't, this makes it clear that the failure is prior to file access but go ahead and check file/directory permissions to make sure the anonymous IIS user can access the file.
Check registry permissions
Using Regedt32, do find on smtpsvg.dll. Check the permissions for the key (and sub keys), and make sure that the anonymous user has read rights. Do a find on the class-id, which contains the location value, and version, and check those permissions as well.
source: http://forums.digitalpoint.com/showthread.php?t=21069

I have had problems in the past with calling .NET assemblies from ASP Classic. I think this was one of the several problems I ran into along the way.
One of the things I had to do to make things work was to make sure the Application Pool for the ASP site was using the same identity as the anonymous user (by default it uses "System User" or something like that). So I ended up creating a new local user (making sure it is a member of the IIS_WPG group) and using that for both the IIS anonymous user and the App Pool identity.
This is a troublesome area though, the app I was using it for was a shrink wrapped product and we found that some machine were screwed up in such a way that we simply couldn't get ASP Classic to .net calls to work even after lots of tweaking of permissions and the like.
Edit:
I guess I should say that I'm not claiming this change will fix this particular problem, just that this was one of the changes we had to make to make out ASP Classic -> .NET code work on a wide range of random customers servers.

I used icepicker's solution and it worked for me. I spent over a day looking into this error i was getting
Microsoft VBScript runtime error '800a01ad'
ActiveX component can't create object: 'namespace.class'
/page.asp, line 15
The solution was to use the c:\Windows\microsoft.net\framework64(folder of framework used)\regasm). I was running this from c:\Windows\microsoft.net\framework64 & c:\Windows\microsoft.net\framework and it did not work. My assumption is that if you run REGASM it will default to the 32 bit version. Unless you specify the framework64/v4.0.x.x.x (or whatever version) folder, only then it will run the 64-bit.

Related

How do I know that my Application loads the correct assemblies?

I have an assembly that is used to verify the security of my Application such as the license.
How do I grant that every time my Application calls the verification method, this is being loaded from the correct assembly?
I want to prevent that someone creates a fake assembly to bypass these verifications.
By adding a .snk to get a Strong Named Key, will this solve my problem?
E.g. If my application uses MySecurity.dll, if someone else creates a assembly with the same name and override it in the bin folder, will my application know that this is not the correct assembly?
I am worried because our solution uses two kinds of verification, local using a public certificate for the license file, and online (if has internet connection). But any of these can be bypassed easily.
You can hard code the hash string of that dll file in your code and check it at run-time (maybe in a timer)
Also you need to protect your assemblies with some thing like this Eazfuscator.NET

How to configure DCOM access, launch and set run as permission using c#

I'm trying to configure access, launch permissions along with set run as to one of our custom DCOM application.
I have already gone through these links
dcomcnfg functionality programmatically
and http://www.myitforum.com/articles/11/view.asp?id=9323 (downloaded c++ DCOMPerm library)
I tried the code from the first link above as is written by "longofest" but the following line of code
var value = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", null);
always gives me back a null value,however when I looked into the registry entries on my machine the "DefaultAccessPermission" entry for Ole registry key does have a binary value there then why I always receive a null back, no idea.
Secondly I tried the c++ library downloaded from the second link above and tried to do a COM call to one of the methods with DLLImport attribution (for automating the launch permissions for the DCOM object) but some marshalling issue is not letting me pass in the C# types corresponding to C++ types and spitting out an exception that says PInvoke cannot return variants.
I couldn't find anything concrete after googling for several hours, any help on this account will be more than appreciated.
Never worked with C++, got very poor knowledge of this language.
Update:The null value issue is solved but I don't know how to set access permissions and set run as. I have seen in c++ code that for setting access permission the code needs a domain and username but what is the c# equivalent of that, no idea....
I used the tblimp.exe tool from Microsoft and created an interop .dll assembly out of DComPerm.dll (c++ assembly) to reference in C# code and by means of Run Time Callable Wrapper I'm calling various methods on COM objects to write my C# program, so no need of DLLImport or MarshalAs attribution since RCW will take care of all the marshalling and unmarshalling issues.

Elevate privileges programmatically on mono

From my mono application, running under Linux, I want to run another one as root user. At the moment I use Process.Start, running gksudo.
This solution works quite well under one condition - there is gksudo installed.
I need a mechanism to elevate privileges for a mono assembly (not necessarily as another process) that does not rely on a particular, desktop-dependant application like gksudo or kdesu and is not console-based (like good ol' sudo).
Actually I believe I need a way to PAM-ify my application.
The solution does not have to be Windows compliant, but it would be a nice bonus.
I've seen many possible answers to my problem, but none did resolve all the issues.
A very nice approach was https://stackoverflow.com/a/16276287/882200, but it requires an assembly to be ran as root, which is not possible.
This inspired me to try a new approach. I've tried running
Process.Start("whoami", "otheruser", password, "");
The output should be otheruser, but it is not.
Please mind that I leave the domain (last parameter) empty (is that OK?) and I fill password according to this example.
This solution is not the best one - it requires me to provide means to grab a password, but it is acceptable, although not working.
The best option for me would be to make my environment choose the correct way to receive a password - either by a Qt/GTK popup or a console prompt.
The last thing to keep in mind - to run an app as root I'd love to be able to provide a sudoer password, not necessarily a root password (according to sudoers configuration).

C# DLL from VBScript, no regasm

Is it possible to access a C# DLL's method from VBScript without registering it with regasm? I will be creating the DLL so pretty much any exotic requirement to make it visible to VBScript, I can do...
I have read here that it might be possible to use GetObject from VBScript to achieve this, but I have tried that with no success... Is there anything else I need to do aside from making the DLL "COM visible" to make this work?
The reason why I need to avoid regasm is that it requires admin rights, and I need to deploy this DLL "silently" to many clients that may or may not have admin rights.
No, registration is required, the only way that the script interpreter can find the DLL that contains the ProgId that you use in the script's CreateObject() call. Isolated COM with a manifest doesn't work, you can't modify the manifest for the script interpreter.
There is a technical solution, you can write registry keys in the HKCU registry hive without acquiring UAC elevation. The Regasm.exe tool always writes them in the HKLM hive. That registers the assembly as well, but only for the user that runs Regasm.exe. It is however pretty painful and easy to get wrong, you have to write your own registration method and apply the [ComRegisterFunction] attribute. It is now your job to use the RegistryKey class to set the keys. Same for the [ComUnregisterFunction], it should delete the keys again. There are a lot of bad examples out on the interwebs, best way to get this right is to use SysInternals' ProcMon to observe the registry keys that get written when you use Regasm.exe normally, then reproduce that in your own code, using HKCU instead.
Do note the other side of that medal, you are in fact making configuration changes to the machine that allows arbitrary code to run. Trying to hide that doesn't do the user any favors and should never be considered if you honor the user's desire to keep the machine safe and predictable. UAC is not there to stop you from making changes, it is only there to inform the user about it.
The accepted answer is incorrect that registration is required to use a DLL. You can use the GetObject() method instead of the CreateObject() method as shown in my answer to this question.
Using DLLs in VBScript

HRESULT:0x80040154 COM object with CLSID {} is either not valid or not registered

I am using COM Object in my C# .NET 1.1 application. When the COM object is not registered on client machine, I get the exception:
"COM object with CLSID {} is either
not valid or not registered."
(HRESULT:0x80040154)
I know how to register the COM object using regsvr32. Our requirement is to identify the COM object which is not registered. We don't want to hardcode the name of the COM Object, rather identify it dynamically using the COM Exception/HResult. Any ideas?
Given the situation mentioned in the comment to Benjamin Podszun's answer, your approach could be:
Look up the CLSID in the registry (HKEY_CLASSES_ROOT\CLSID\{...})
If not found, just throw so that the generic error message is displayed
Look at the appropriate subkey depending on the type of object (e.g. InProcServer32 for an in-proc native COM DLL/OCX). The default value will be the path to the DLL/OCX.
Check for the existence of this path and fabricate a suitable message with the name of the file.
This enables you to display a different message if the OCX/DLL has been moved, but of course won't help if it is not registered.
You also might want to spend some time trying to understand why (or even five whys!) the components are being moved / unregistered on some client machines, which may suggest a way to prevent it . For example, one possible scenario is that the user installs version 1, then installs version 2, then uninstalls version 1. Depending on how your installer is implemented, uninstalling version 1 may deregister or remove the components needed for version 2.
Another approach might be to see how the installer behaves as a normal user vs an administrator.
Identifying the exact sequence of events on failing client machines may be a bit of a challenge, but it's worth trying.
The only way to solve the problem you describe is to have a global list of CLSIDs for all objects you want to check.
If you only care about a few libraries, you can install them, check their GUIDs, and build this database yourself.
If you want to identify any possible library worldwide that might ever exist, I would give up now and have some coffee.
If I understand you correctly you get the message "I don't know how to find the COM object for this GUID" and want to do it better..?
In other words: Usually you'd register the COM object and it is referenced by its class id or ProgId. For now windows doesn't know about your target object.
I'm not sure how to do that. If your COM objects are .Net assemblies you might be able to use Reflection to iterate over a list of files in your program directory and lookup the relevant attribute, comparing it with the error message.
If they are native libraries there are probably P/Invoke ways to do the same, but I wouldn't know how and Google doesn't help so far.
I would love to understand the requirement though: Since you're distributing that app and know the dependencies, why do you want to add this extra layer of complexity?

Categories