Do the audit logs show any permission issues? (It may be necessary to enable all system events to understand if the problem is related to login, service permissions, resources, etc.)
- Log in to post comments
Do the audit logs show any permission issues? (It may be necessary to enable all system events to understand if the problem is related to login, service permissions, resources, etc.)
If the access is via SQL (INSERT, UPDATE), it is possible.
You can create a role with RW access to the database resource and grant INSERT privileges without the SELECT privilege.
If the access is via Global (SET), it is not so simple. Because you need to grant RW permission to the Database Resource and, consequently, the user will be able to read the data from the global resource.
For example, you create the logs_w role and grant it to the user
%SYS>do ##class(Security.Roles).Create("logs_w", "", "%DB_LOGS:RW")
%SYS>do ##class(%SQL.Statement).%ExecDirect(,"GRANT logs_w TO appuser")
%SYS>set $NAMESPACE="LOGS"
LOGS>do ##class(%SQL.Statement).%ExecDirect(,"GRANT INSERT ON app.Log TO logs_w")If the user tries to execute a SELECT they will receive an error
LOGS>do $SYSTEM.Security.Login("appuser")
LOGS>do $SYSTEM.SQL.Shell()
[SQL]LOGS>>SELECT * FROM app.Log
ERROR #5540: SQLCODE: -99 Message: User appuser is not privileged for the operationIf the user tries to execute an INSERT, it will succeed.
[SQL]LOGS>>INSERT INTO app.Log VALUES ('Test 1')
1. INSERT INTO app.Log VALUES ('Test 1')
1 Row Affected
---------------------------------------------------------------------------But this permission is not valid for globals, the user will be able to read
LOGS>zw ^app.LogD
^app.LogD=1
^app.LogD(1)=$lb("","Test 1")In this case you can follow other strategies, such as Applications and Privilege Escalation. Here you isolate the database and the user does not have default access when logging in. Access is granted temporarily when executing a method/routine. A simple example:
In a database to which the user has default access, create a method that receives temporary privileges to write to the protected database
Class service.Log
{
ClassMethod write(msg As %String) As %Status
{
do $SYSTEM.Security.AddRoles("grant_logs_w")
new $NAMESPACE
set $NAMESPACE="LOGS"
do ##class(%SQL.Statement).%ExecDirect(,"INSERT INTO app.Log VALUES (?)", msg)
return 1
}
}Create a Privileged Routine Applications for this method
set p("Name") = "grant_logs_w"
set p("CookiePath") = "grant_logs_w/"
set p("Description") = "Applications and Privilege Escalation"
set p("Type") = 4
set p("Resource") = "%Development"
set p("AutheEnabled") = 64
set p("Enabled") = 1
set p("MatchRoles") = ":logs_w"
set p("Routines") = "service.Log:APP:1"
do ##class(Security.Applications).Create("grant_logs_w", .p)The user does not have access to the LOGS database, but can execute the write method with temporary privileges.
APP>w $ROLES
%Developer,%DB_APP
APP>do ##class(service.Log).write("Test 2")You may find more information in this legacy documentation:
https://docs.intersystems.com/latest/csp/docbook/Doc.View.cls?KEY=GDOC_legacy
Hi Philip,
Another way is to use the ##class(Backup.General).IsWDSuspendedExt() routine.
According to the documentation:
"When called in an external script, exit status is set to 5 if WD is suspended or 3 otherwise."
Example:
irisowner:~$ iris terminal IRIS -U%SYS "##class(Backup.General).ExternalFreeze()"
irisowner:~$ iris terminal IRIS -U%SYS "##class(Backup.General).IsWDSuspendedExt()"
irisowner:~$ echo $?
5
irisowner:~$ iris terminal IRIS -U%SYS "##class(Backup.General).ExternalThaw()"
irisowner:~$ iris terminal IRIS -U%SYS "##class(Backup.General).IsWDSuspendedExt()"
irisowner:~$ echo $?
3
Maybe it can help,
In the SYS.Database Class you can find the IsSystemDB(Directory) method that returns whether it is a system database.
It works on Caché and IRIS.
Documentation IsSystemDB - IRIS
Documentation IsSystemDB - Caché
Examples:
%SYS>set databaseDir = ##class(Config.Databases).Open("IRISLIB").Directory
%SYS>write ##class(SYS.Database).IsSystemDB(databaseDir)
1%SYS>set databaseDir = ##class(Config.Databases).Open("CACHELIB").Directory
%SYS>write ##class(SYS.Database).IsSystemDB(databaseDir)
1Hi Shen Jun,
If you installed Caché on Windows before installing the Windows SNMP service. You need to register the DLL in Caché. Open the Terminal and type:
%SYS> set status=$$Register^SNMP()
Then restart the Windows SNMP service and start the Caché SNMP service.
Documentation: SNMP Troubleshooting
Have you already done this step?
You can create User Events using the Security.Events class, with the Create method.
Example:
I suggest reading the article: InterSystems Data Platforms and Performance Part 4 - Looking at Memory
This process is related to the Caché System Monitor. Monitors various resources, including the Journal.
"Caché System Monitor is a flexible, user-extensible utility used to monitor a Caché instance and generate notifications when the values of one or more of a wide range of metrics indicate a potential problem."
You can Stop them or customize the Sampling Interval for your environment.
See more in the documentation Caché System Monitor and Caché Monitor
You can try to change using Config.SQL class.
Example:
%SYS>w $SYSTEM.SQL.CurrentSettings()
ODBC VARCHAR Max Length: 4096 (Default)
%SYS>do ##class(Config.SQL).Get(.p)
%SYS>zw p("ODBCVarcharMaxlen")
p("ODBCVarcharMaxlen")=4096
%SYS>set p("ODBCVarcharMaxlen") = 5120
%SYS>do ##class(Config.SQL).Modify(.p)
%SYS>w $SYSTEM.SQL.CurrentSettings()
ODBC VARCHAR Max Length: 5120The same example but in a different form:
try {
set result=##class(%ResultSet).%New("%DynamicQuery:SQL")
$$$ThrowOnError(result.Prepare("SELECT ... "))
} catch error {
do error.Log()
}The error details will be in the Application Error Log
In Caché, as an alternative to Portal, you can use Terminal and run:
SAMPLES>do $SYSTEM.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------
Or the %SQL.Statement
Or try an external tool like dbeaver (https://dbeaver.io/)
Another suggestion,
If you use an exclusive Resource in your database (example %DB_<database-name>), you can use it as a reference. It is included in the .DAT and you can check it even with the database not created, just the physical file.
Example:
w ##class(SYS.Database).%OpenId("/usr/irissys/mgr/test1/").ResourceName
The SYS.Database class also gets other information, but nothing relevant for identification.
--
Or (perhaps not recommended) you can extract the original path directly from the .DAT, for example:
$ strings /usr/irissys/mgr/test2/IRIS.DAT | head -3
Cache DB
/usr/irissys/mgr/test1/
%DB_TEST1
You can review the 'UnknownUser' user's permissions. In the documentation it says that 'Embedded SQL' does not check permissions:
InterSystems SQL enforces privilege checking for ODBC, JDBC, Dynamic SQL, and the SQL Shell interface on InterSystems IRIS data platform. Embedded SQL statements do not perform privilege checking;
Or use an authenticated user with the proper permissions;
About privileges and users: Users, Roles, and Privileges
About authentication: Authentication and Authorization
Based on the ODBC source program maybe you can get it with Delegated Authentication. Depending on the origin, the user would receive additional Roles or not with (Using Privileged Routine Applications).
To create additional or specific Roles for each user or user group see RBAC documentation.
I didn't know about this change in IRIS. Thanks for clarifying.
You can also try rebuilding the Index Table or clearing Cached Queries. Portal uses cached query and in its code it uses Embedded SQL (&sql) - Doc.: There is no need for a cache for Embedded SQL, because Embedded SQL statements are replaced with inline code at compilation time.
I'm using Zabbix to monitor all IRIS status and it works great. Zabbix has alert features (Triggers) that communicate with me via email or communication channels (like slack) when an incident occurs. I collect status information, errors, performance, etc. I use SNMP protocol indicators and other indicators through ODBC, some created by me and others obtained through monitor collections.
You can try this using EmergencyId mode. Stop IRIS and start with the parameter:
Linux
iris start IRIS EmergencyId=user,passwordWindows
iris start IRIS /EmergencyId=user,passwordUser and password can be anything. This will be used for login.
Once logged in as this user by the terminal, you can use the ^SECURITY routine in the %SYS namespace to change the password of _SYSTEM.
Documentation (Temporary):
As @Danny Wijnschenk said, on Windows it needs to be /EmergencyId=.
There are a few more instructions in the Documentation, like "Start a command prompt, running it as an administrator", etc.
In Caché I use this:
set path = ##class(Config.Databases).Open("USER").Directoryset database = ##class(SYS.Database).%OpenId($get(path)) do database.DisableJournaling() set status = database.%Save() do database.EnableJournaling() set status = database.%Save()
I also don't know the %SQL_Manager.CachedQueryTree() and I didn't find it in the Doc. I don't know if there's a difference.
At Caché I usually use it:
SELECT Routine, Query FROM %Library.SQLCatalog_SQLCachedQueryInfo()Is there a difference?
Very useful. I have had this problem many times.
Hi @Robert Cemper , I'm going to do some tests with your example, thank you!
Thank you @Igor Titarenko , it is exactly what I was looking for.
Thank you Evgeny and Benjamin for answering.
I used the method store procedure to solve this recursion problem.
Maybe the "Next" method is missing.
Ex:
SET rs = ##class(%SQL.Statement).%ExecDirect(, "SELECT * FROM LISDB.ExternalUsers WHERE UserId = 83")
do rs.%Next()
write rs.%Get("Prefix")
If that doesn't work, put the command sequence you're running.
Usually, I follow the order of indexes or column selectivity (this is a general rule in all databases). For large tables or complex queries, this can influence. However, it seems that the Caché SQL optimizer chooses the best query plan.
You can try to use %IGNOREINDEX